2

I'm creating a simple AWS Lambda Function in Java that creates and returns a PDF. The function is invoked by an API Gateway. The input is a simple POJO class, but the output should be an OutputStream for the file.

For the input, I've tried creating a POJO class and just using the APIGatewayProxyRequestEvent and either works fine. Below is a simple example I used that takes in a input and prints back the query string parameters.

public class LambdaFunctionHandler implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {

    @Override
    public APIGatewayProxyResponseEvent handleRequest( APIGatewayProxyRequestEvent input, Context context ) {

        return new APIGatewayProxyResponseEvent()
            .withStatusCode(200)
            .withHeaders(Collections.emptyMap())
            .withBody("{\"input\":\"" + input.getQueryStringParameters() + "\"}");
    }

}

That works fine, but now I need to alter it to use an OutputStream as the the output. How can this be done? I see that I can use the RequestStreamHandler and AWS has some documentation on implementing this. However, that would force my input to be an InputStream, which I'm not sure how that would work with the API Gateway.

How can I serve this PDF back to the client requesting it?

1
  • Can't you just set the type of the response to OutputStream (both in the method declaration and in the interface)? Commented Nov 15, 2019 at 16:23

1 Answer 1

1

Remember that the POJO method of the Lambda handler is a convenience only. Ultimately, you could do this yourself and use the InputStream/OutputStream Lambda pattern. Something like:

public void handleRequest(InputStream inputStream,
                          OutputStream outputStream,
                          Context context) throws IOException {
    String inputString = new BufferedReader(new InputStreamReader(inputStream)).lines().collect(Collectors.joining("\n"));

    ObjectMapper objectMapper = new ObjectMapper();
    APIGatewayProxyRequestEvent request = objectMapper.readValue(inputString, APIGatewayProxyRequestEvent.class);

    // do your thing, generate a PDF
    byte[] thePDF = ...
    // create headers
    Map<String, String> headers = new HashMap<>();
    headers.put("Content-type", "application/pdf");

    APIGatewayProxyResponseEvent response = new APIGatewayProxyResponseEvent().
             .withStatusCode(200)
             .withHeaders(headers)
             .withBody(Base64.Encoder.encode(thePDF))
             .withIsBase64Encoded(Boolean.TRUE);

    outputStream.write(objectMapper.writeValueAsString(response)
                                   .getBytes(StandardCharsets.UTF_8));
}

However, I'm not convinced that this is really any better. If you want to return just the PDF without the APIGatewayProxyResponseEvent you can but now you'll have to update API Gateway to correctly send the Content-Type header.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, this is helpful. In the response builder, withBody will only take a String. So it seems like I'll have to convert it there. In the API gateway, I had to disable Lambda Proxy Integration. Also, it appears that the actual PDF is not being sent, but instead, a JSON output. For instance, I'm getting this {"statusCode":200,"headers":{"Content-type":"application/pdf"},"body":"[B@59ec2012","isBase64Encoded":true} I mostly just need to do a bit more research on my end. But right now, I can't quite figure out how to get the binary data back to the client with the correct content-type.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.