AWS Lambda - Java Bean

NoI*_*his 10 java scala aws-lambda aws-api-gateway serverless-framework

我有一个如下所示的请求:

package pricing

import scala.beans.BeanProperty

class Request(@BeanProperty var name: String, @BeanProperty var surname: String) {
  def this() = this(name="defName", surname="defSurname")
}
Run Code Online (Sandbox Code Playgroud)

处理程序如下:

package pricing

import com.amazonaws.services.lambda.runtime.{Context, RequestHandler}
import scala.collection.JavaConverters
import spray.json._


class ApiGatewayHandler extends RequestHandler[Request, ApiGatewayResponse] {

  import DefaultJsonProtocol._

  def handleRequest(input: Request, context: Context): ApiGatewayResponse = {
    val headers = Map("x-foo" -> "coucou")
    val msg = "Hello " + input.name
    val message = Map[String, String]("message" -> msg )
    ApiGatewayResponse(
      200,
      message.toJson.toString(),
      JavaConverters.mapAsJavaMap[String, Object](headers),
      true
    )
  }
}
Run Code Online (Sandbox Code Playgroud)

已被记录为:

functions:
  pricing:
    handler: pricing.ApiGatewayHandler
    events:
      - http:
          path: pricing/test
          method: get
          documentation:
            summary: "submit your name and surname, the API says hi"
            description: ".. well, the summary is pretty exhaustive"
            requestBody:
              description: "Send over name and surname"
            queryParams:
              - name: "name"
                description: "your 1st name"
              - name: "surname"
                description: ".. guess .. "
            methodResponses:
              - statusCode: "200"
                responseHeaders:
                  - name: "x-foo"
                    description: "you can foo in here"
                responseBody:
                  description: "You'll see a funny message here"
                responseModels:
                  "application/json": "HelloWorldResponse"
Run Code Online (Sandbox Code Playgroud)

好吧,这是其中一个教程的复制和粘贴.它不起作用.我猜这是BeanProperty指身体对象的属性; 这就是我从这个例子中可以猜到的here.

如果我想查询字符串?

试一试:

package pricing

import scala.beans.BeanProperty
import spray.json._

abstract class ApiGatewayGetRequest(
                                     @BeanProperty httpMethod: String,
                                     @BeanProperty headers: Map[String, String],
                                     @BeanProperty queryStringParameters: Map[String, String])


abstract class ApiGatewayPostRequest(
                                     @BeanProperty httpMethod: String,
                                     @BeanProperty headers: Map[String, String],
                                     @BeanProperty queryStringParameters: Map[String, String])

class HelloWorldRequest(
                         @BeanProperty httpMethod: String,
                         @BeanProperty headers: Map[String, String],
                         @BeanProperty queryStringParameters: Map[String, String]
                       ) extends ApiGatewayGetRequest(httpMethod, headers, queryStringParameters) {

  private def getParam(param: String): String =
    queryStringParameters get param match {
      case Some(s) => s
      case None => "default_" + param
    }

  def name: String = getParam("name")
  def surname: String = getParam("surname")

  def this() = this("GET", Map.empty, Map.empty)

}
Run Code Online (Sandbox Code Playgroud)

结果如下:

 {
  "message":"Hello default_name"
 }
Run Code Online (Sandbox Code Playgroud)

建议使用空地图初始化类,queryStringParameters而不是正确提交的地图

 Mon Sep 25 20:45:22 UTC 2017 : Endpoint request body after
 transformations:
 {"resource":"/pricing/test","path":"/pricing/test","httpMethod":"GET","headers":null,"queryStringParameters":{"name":"ciao", "surname":"bonjour"},"pathParameters":null,"stageVariables":null,
 ...
Run Code Online (Sandbox Code Playgroud)

注意:我遵循这条路径,因为我觉得用类型T 替换Mapin 会很方便和富有表现力@BeanProperty queryStringParameters: Map[String, String]

case class Person(@beanProperty val name: String, @beanProperty val surname: String)
Run Code Online (Sandbox Code Playgroud)

但是,上面的代码{"name":"ciao", "surname":"bonjour"}看作是一个String,但没有弄清楚它应该反序列化该String.

编辑

我也尝试用一个java.util.Map[String, String]没有成功的替换scala地图

izs*_*tas 5

默认情况下,Serverless启用lambda和API Gateway之间的代理集成.这对您来说意味着API Gateway将把包含有关请求的所有元数据的对象传递给您的处理程序,正如您所注意到的:

星期一9月25日20:45:22 UTC 2017:转换后的端点请求体:{"resource":"/ pricing/test","path":"/ pricing/test","httpMethod":"GET","header" ":null,"queryStringParameters":{"name":"ciao","surname":"bonjour"},"pathParameters":null,"stageVariables":null,...

这显然不会映射到只有字段name和其中的模型surname.有几种方法可以解决这个问题.

1.调整您的模型

HelloWorldRequest如果通过使字段可变(并因此为它们创建setter)使您的类成为正确的POJO,那么您对该类的尝试确实有效:

class HelloWorldRequest(
                         @BeanProperty var httpMethod: String,
                         @BeanProperty var headers: java.util.Map[String, String],
                         @BeanProperty var queryStringParameters: java.util.Map[String, String]
                       ) extends ApiGatewayGetRequest(httpMethod, headers, queryStringParameters) {
Run Code Online (Sandbox Code Playgroud)

AWS Lambda文档说明:

为了让POJO与AWS Lambda的内置JSON序列化程序一起使用,需要get和set方法.

另请注意,不支持Scala的地图.

2.使用自定义请求模板

如果您不需要元数据,那么您可以使用映射模板将API网关仅传递到lambda中,而不是更改模型.

为此,您需要告诉Serverless使用普通的lambda集成(而不是代理)并指定自定义请求模板.

Amazon API Gateway文档有一个示例请求模板,几乎可以完美解决您的问题.我们得到了一点点量身定做

functions:
  pricing:
    handler: pricing.ApiGatewayHandler
    events:
      - http:
          path: pricing/test
          method: get
          integration: lambda
          request:
            template:
              application/json: |
                #set($params = $input.params().querystring)
                {
                #foreach($paramName in $params.keySet())
                  "$paramName" : "$util.escapeJavaScript($params.get($paramName))"
                  #if($foreach.hasNext),#end
                #end
                }
Run Code Online (Sandbox Code Playgroud)

此模板将从查询字符串参数中生成JSON,现在它将成为lambda的输入:

转换后的端点请求体:{"name":"ciao"}

哪个映射到您的模型.

请注意,禁用代理集成也会更改响应格式.您会注意到,现在您的API会直接返回您的响应模型:

{"statusCode":200,"body":"{\"message \":\"Hello ciao \"}","headers":{"x-foo":"coucou"},"base64Encoded":true}

您可以通过修改代码以仅返回正文或添加自定义响应模板来解决此问题:

          response:
            template: $input.path('$.body')
Run Code Online (Sandbox Code Playgroud)

这会将输出转换为您所期望的,但会公然忽略statusCodeheaders.您需要制作更复杂的响应配置来处理这些问题.

3.自己做映射

相反延伸RequestHandler,让AWS LAMBDA的JSON映射到一个POJO,你可以去继承RequestStreamHandler,这将为您提供一个InputStreamOutputStream,这样你就可以与您所选择的JSON序列做(德)序列化.