Coding just likes Art
This is the blog about the coding, the whole coding and nothing but the coding , so God would help me become a better developer.

The Response of AWS Gateway When Lambda Return Nothing

1 Why

We were trying to handle the error after we built a AWS lambda and API gateway micro-service with Scala. One case was when something wrong with writing the response data into the OutputStream, what could happen? Since nothing would be put into the OutputStream, the API gateway cannot get the response status and entity from that stream. I couldn't find any clue from AWS official document, so I decided to give it a try.

2 For NodeJS

AWS lambda allows us to implement the functionality by using three languages: Python, JavaScript, and Java. I am not familiar with python, so I decided to try node first.

exports.myHandler = function(event, context, callback) {
   callback(null, null); // Get same result if this line is deleted
};

After test, I got a 502 status with the response body like the following:

{
  "message": "Internal server error"
}

And the log show more informations:

Tue Nov 08 01:28:47 UTC 2016 : Endpoint response body before transformations: null
Tue Nov 08 01:28:47 UTC 2016 : Endpoint response headers: {x-amzn-Remapped-Content-Length=0, x-amzn-RequestId=*********-a552-11e6-8982-e3ac77aaf27f, Connection=keep-alive, Content-Length=4, Date=Tue, 08 Nov 2016 01:28:47 GMT, Content-Type=application/json}
Tue Nov 08 01:28:47 UTC 2016 : Execution failed due to configuration error: Malformed Lambda proxy response
Tue Nov 08 01:28:47 UTC 2016 : Method completed with status: 502

3 Run in JVM

The beauty of the AWS lambda is that it not only support JAVA but also any language that has the capability of running in JVM. So it means that languages like Scala, Ruby, and Closure could also be used to built a lambda.

Here is my test handler:

package tech.jmqu

import java.io.{OutputStream, InputStream}
import com.amazonaws.services.lambda.runtime.Context

object LambdaTest {
  def handle(input: InputStream, output: OutputStream, context: Context): Unit = {
    input.close()
    output.close()
  }
}

Here is my Built.scala for sbt:

import sbt._, Keys._
import sbtassembly.{PathList, MergeStrategy}
import sbtassembly.AssemblyKeys._

object AppBuild extends Build {
  val appDependencies = Seq(
    "com.amazonaws" % "aws-lambda-java-core" % "1.1.0",
    "com.amazonaws" % "aws-lambda-java-events" % "1.3.0"
  )

  val projectSettings = Defaults.coreDefaultSettings ++ Seq(
    name := "test",
    version := "0.1-SNAPSHOT",
    scalaVersion := "2.11.5",
    sbtVersion := "0.13.11",
    scalacOptions ++= Seq(
      "-Xfatal-warnings",
      "-deprecation",
      "-feature",
      "-encoding", "UTF-8"
    ),
    javaOptions ++= Seq("-encoding", "UTF-8"),
    libraryDependencies ++= appDependencies,
    assemblyJarName in assembly := s"test.jar",
    mergeStrategy in assembly := {
      case PathList("META-INF", xs @ _*) => MergeStrategy.discard
      case x => MergeStrategy.first
    }
  )

  lazy val project = Project("test", file("."),
    settings = projectSettings
  )
}

And here is my plugin.sbt:

addSbtPlugin("io.get-coursier" % "sbt-coursier" % "1.0.0-M14")
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.3")

After sbt assembly and uploaded to S3, I deployed to the lambda. I got the same result: Status 502 with the body:

{
  "message": "Internal server error"
}

But the log in API gateway is a little different:

Mon Nov 07 15:36:32 UTC 2016 : Endpoint response body before transformations:
Mon Nov 07 15:36:32 UTC 2016 : Endpoint response headers: {x-amzn-Remapped-Content-Length=0, x-amzn-RequestId=*******-a4ff-11e6-b40b-430392a24fcf, Connection=keep-alive, Content-Length=0, Date=Mon, 07 Nov 2016 15:36:31 GMT, Content-Type=application/json}
Mon Nov 07 15:36:32 UTC 2016 : Execution failed due to configuration error: Malformed Lambda proxy response
Mon Nov 07 15:36:32 UTC 2016 : Method completed with status: 502

4 Conclusion

The status 502 is for Bad Gateway, but the cause is from lambda. So it doesn't make any sense. So we should always avoid to response an null body in lambda. But we still cannot ensure that, so here is the solution.

The API gateway allows us to set up the pattern regex in Integration Response for certain request method in Resources, it support Lambda Error Regex. So after I setting up with following:

Lambda Error Regex Method response status
.+ 200
^$ 500

I got a null response body with 500 status.