AWS Lambda - Java Beans

10

我有一个类似以下内容的请求:

package pricing

import scala.beans.BeanProperty

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

处理程序如下所示:
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
    )
  }
}

这被记录为:

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"

好的,这是从教程中复制粘贴的内容。但它并没有起作用。我猜测BeanProperty是指body对象属性;这是我从这里的示例中所猜测的。

如果我想要查询字符串怎么办?

尝试如下:

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)

}

这导致:
 {
  "message":"Hello default_name"
 }

提示该类已使用空映射初始化,代替正确提交的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,
 ...

注意: 我选择这个路径是因为我认为用类型T(例如)替换 @BeanProperty queryStringParameters: Map[String, String] 中的 Map 更加方便和表达清晰。
case class Person(@beanProperty val name: String, @beanProperty val surname: String)

然而,上面的代码将{"name":"ciao", "surname":"bonjour"}视为一个String,而没有弄清楚它应该反序列化那个字符串。 编辑 我还尝试将scala map替换为java.util.Map[String, String],但没有成功。

你能以任何方式获取像 {"name":"ciao", "surname":"bonjour"} 这样的字符串返回吗?如果可能的话,你能否创建一个对象来保存(从字符串解析出来的)数据?对于你来说,将字符串条目解析为Java对象是一种可行的解决方案吗? - VC.One
1个回答

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

Mon Sep 25 20:45:22 UTC 2017:转换后的端点请求正文:{"resource":"/pricing/test","path":"/pricing/test","httpMethod":"GET","headers":null,"queryStringParameters":{"name":"ciao", "surname":"bonjour"},"pathParameters":null,"stageVariables":null, ...

这显然与您的模型不匹配,因为它只有字段namesurname。你可以采取几种方法来解决这个问题。

1.调整您的模型

如果您使字段可变(从而为它们创建setters),您使用HelloWorldRequest类的尝试实际上是有效的:
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) {

AWS Lambda文档中指出:get和set方法对于使POJO能够使用AWS Lambda的内置JSON序列化程序是必需的。另外需要注意的是,Scala的Map不被支持。
2. 使用自定义请求模板
如果您不需要元数据,则可以使用映射模板让API Gateway仅将所需数据传递给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
                }

这个模板将查询字符串参数转换为JSON,现在它将成为Lambda函数的输入:

经过转换的端点请求正文:{"name":"ciao"}

这将正确映射到您的模型中。

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

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

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

          response:
            template: $input.path('$.body')

这将把输出转换为您所期望的结果,但将公然忽略 statusCodeheaders。您需要制作一个更复杂的响应配置来处理它们。

3. 自行进行映射

不要扩展RequestHandler并让AWS Lambda将JSON映射到POJO,而是可以扩展RequestStreamHandler,这将为您提供InputStreamOutputStream,因此您可以使用您选择的JSON序列化器进行(反)序列化。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接