How do I change status and headers when streaming with lambda and function url?

1

Hello,

I'm new to working with AWS Lambda and streaming HTTP responses. I've been following this tutorial and specifically the "Create a response streaming function (AWS CloudFormation)" section. In that section, they use awslambda.HttpResponseStream.from to add metadata to the stream. However, when I implemented a similar Lambda handler, the result was not what I expected. Instead of adding the metadata to the response, it concatenated it with the response body.

Here's the code I used:

export const handler = awslambda.streamifyResponse(
  async (ev: APIGatewayProxyEventV2, stream: ResponseStream) => {
    const metadata = {
      status: 404,
      headers: {
        'Content-Type': 'text/html',
        'Cache-Control': 'no-cache',
      },
    }

    stream = awslambda.HttpResponseStream.from(stream, metadata)
    stream.setContentType('text/html')

    stream.write('Not found!')
    await new Promise((resolve) => setTimeout(resolve, 1000))
    stream.write('text1')
    await new Promise((resolve) => setTimeout(resolve, 1000))
    stream.write('text2')
    await new Promise((resolve) => setTimeout(resolve, 1000))
    stream.end()
  },
)

My goal is to change the response status and headers dynamically within the Lambda function. Is there a way to achieve this? I would appreciate any guidance or suggestions.

Thank you in advance!

  • I also noticed that responseStream.finished(), used in the example I said before, doesn't exist.

  • Where did you import the TypeScript type ResponseStream from?

  • I was importing it from this package https://github.com/astuyve/lambda-stream but I found a better solution for the awslambda types

    import type { Writable } from 'stream'
    
    import type { APIGatewayProxyEventV2, Context, Handler } from 'aws-lambda'
    
    declare global {
      namespace awslambda {
        export namespace HttpResponseStream {
          function from(writable: Writable, metadata: any): Writable
        }
    
        export type ResponseStream = Writable & {
          setContentType(type: string): void
        }
    
        export type StreamifyHandler = (
          event: APIGatewayProxyEventV2,
          responseStream: ResponseStream,
          context: Context,
        ) => Promise<any>
    
        export function streamifyResponse(
          handler: StreamifyHandler,
        ): Handler<APIGatewayProxyEventV2>
      }
    }
profile picture
asked 10 months ago846 views
2 Answers
0
Accepted Answer

For anyone who having the same issue, check your metadata, it seems that awslambda.HttpResponseStream will not apply the metadata if one of the properties is invalid. In my example, I spelled status instead of statusCode

profile picture
answered 10 months ago
-1

Here is an excerpt from the response streaming blog post :

Response streaming currently supports the Node.js 14.x and subsequent managed runtimes. You can also implement response streaming using custom runtimes. You can progressively stream response payloads through Lambda function URLs, including as an Amazon CloudFront origin, along with using the AWS SDK or using Lambda’s invoke API. You can not use Amazon API Gateway and Application Load Balancer to progressively stream response payloads, but you can use the functionality to return larger payloads with API Gateway.

So I would guess you are trying to view the headers using an API Gateway proxy to your lambda. Following the same tutorial you linked, I was able to get the response streaming working using Lambda Function URLs and curl. I also validated that the metadata set in the function was returned in the headers of the curl request, so it is possible to change the response status and headers dynamically within the Lambda function as you asked.

profile pictureAWS
answered 10 months ago
  • I'm not using API Gateway. I'm using my Function URL as one of my cloudfront's origin, but even requesting through the URL itself the metadata is returned concatenated to the body. Here's the curl header's response to my example:

    HTTP/1.1 200 OK
    Date: Fri, 07 Jul 2023 20:13:55 GMT
    Content-Type: text/html
    Transfer-Encoding: chunked
    Connection: keep-alive
    x-amzn-RequestId: 71ff8318-56fd-4eaf-81cc-6a8a03dc8ae2
    X-Amzn-Trace-Id: root=1-64a87203-148a57e50f6bf083130096db;sampled=0;lineage=e344ae8b:0
    

    And here's the body:

    {"status":404,"headers":{"Content-Type":"text/plain","Cache-Control":"no-cache"}}    Not found!text1text2
    

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions