Set up response template for redirect

When I use serverless v0.5, I was able to easily set up a 302 status code in the s-function.json file like below.

 "default": {
     "statusCode": "302",
           "responseParameters": {
             "method.response.header.Location": "integration.response.body.location"
           }...

But, I couldn’t find the way to specify the 302 status code and responseParameter in a serverless.yml (Serverless v1.0-rc). Is there a way of doing this?

4 Likes

I was looking for this too. It looks like the 1.0 RC’s are hard coded for a limited number of response codes. There is a plugin that might help with this https://github.com/silvermine/serverless-plugin-multiple-responses

2 Likes

Thank you for sharing the plugin!
This plugin will suffice to set up the custom responses. :slight_smile:

With the latest master and the proxy integration you can simply return the status code from code now. This should make this a lot simpler.

2 Likes

Hi @flomotlik, can you elaborate on this? How would one return a 302 status code along with URL to redirect to?

The proxy integration allows you to set headers and status code directly so you simply set the 302 status code and the applicable header (e.g. Location:) and you should be all set:

apigateway proxy: http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-set-up-simple-proxy.html

Our docs are currently a bit wrong as you shouldn’t use the context.succeed method, but simply use the callback that is also provided. But you get the picture from here:

Our documentation: https://serverless.com/framework/docs/providers/aws/events/apigateway/

Hi @flomotlik, I still can’t get this to work.

Here’s my lambda function:

module.exports.testRedirect = (event, context, callback) => {
  const response = {
    statusCode: 302,
    headers: {
      "Location": "https://www.google.co.uk"
    }
  };

  callback(null, response);
};

And here’s my yaml configuration:

functions:
  testRedirect:
    handler: handler.testRedirect
    events:
    - http:
        path: test
        method: get
        integration: lambda-proxy

I’ve tried both “lambda” and “lamda-proxy” integrations, but all I get back is the full response JSON in the browser. Am I missing something in my configuration?


Update: @flomotlik Thank you - that works now with the “body” specified. It’s a shame serverless-offline doesn’t support it.

The response object doesn’t have a body config. Maybe that is the issue. And also check that you have Serverless 1.0.2 installed.

module.exports.testRedirect = (event, context, callback) => {
  const response = {
    statusCode: 302,
    headers: {
      "Location": "https://www.google.co.uk"
    },
    body: ""
  };

  callback(null, response);
};
1 Like

@flomotlik do you have an example of the equivalent of this when using Java? I tried returning a string of JSON with the similar fields, but that didn’t work (it just passes the JSON straight through to the response/browser). I don’t see a mapping in the AWS API Gateway config that seems like it’d handle a 302, so I’m wondering if this is feasible with Java? If there are any docs for Java examples of this stuff, please point me to that as I may just not be aware of those.

I should note, I have also tried throwing an exception, and combining that with a response mapping. However, I can’t seem to use a dynamic Location header value, as when I deploy I’m told “Invalid mapping expression”. Here’s what I have for the yaml config:

functions:
  oauthcallback:
    handler: LambdaHandler::oauth_callback
    events:
      - http:
          path: oauth/callback
          method: get
          integration: lambda
          request:
            template:
              application/json: '{ "code" : "$input.params(''code'')" }'
          response:
            statusCodes:
              302:
                pattern: ''
                headers:
                  Location: $input.path("$.errorMessage")

Note, I tried a template in the response, and that properly uses that same dynamic value, so it may just be that Serverless doesn’t allow a dynamic header value?

I’d still be interested in knowing if there is a better way to do this, or way to use the default mappings and not raise an exception to achieve this, etc.

@chris You seem to be mixing lambda and lambda proxy integration type. Returning a JSON response with statusCode, headers and body will only work if you’re using lambda-proxy in which case you don’t need the request and response sections in your serverless.yml (you also don’t need the integration: lambda either as it defaults to lambda-proxy).

Assuming your serverless.yml now looks like:

functions:
  oauthcallback:
    handler: LambdaHandler::oauth_callback
    events:
      - http:
          path: oauth/callback
          method: get

Now you just need to write your Lambda function so that it returns a Java bean with statusCode, headers and body properties. Based on the Java examples in the AWS docs I would expect the response class to look something like:

class ResponseClass {
  private string statusCode;

  public string getStatusCode() {
    return this.statusCode;
  }

  public void setStatusCode(string statusCode) {
    this.statusCode = statusCode;
  }

  ...
}

@buggy thanks. So, that allows me to do a proper response, but I can’t seem to get the query parameter without doing a mapping (or I’m just not understanding). JSON data from a POST tends to work, but I haven’t seen how to get a query parameter with a GET to work. I am using the POJO approach for my handler (vs. inheriting from the interface). I have a class that has a “code” property, but it never gets set from the “code” query parameter (which is why I had that request template mapping before). Any guidance there? Are query parameters maybe mapped a different way (when I’ve used the JavaScript implementation, I know I had to get them from event.pathParameters.

I happen to be doing all this in Kotlin, so it’s possible there is something not translating right, but I’ve done Lambda handlers in Kotlin this same way before and it worked fine (I’ve just never had to use query params, it was always JSON data sent to a POST, which got mapped into my request object just fine).

@chris
Query parameters in proxy integration can be obtained via event.queryStringParameters which is a map of strings.
I am using the following mapping in my framework: https://github.com/bbilger/jrestless/blob/master/aws/gateway/jrestless-aws-gateway-core/src/main/java/com/jrestless/aws/gateway/io/GatewayRequest.java
And/Or
https://github.com/bbilger/jrestless/blob/master/aws/gateway/jrestless-aws-gateway-handler/src/main/java/com/jrestless/aws/gateway/io/GatewayRequestImpl.java

@bbilger thank you! I have it all working now. The key was adding a queryStringParameters field to my request object. Since I only needed that, and only needed a single element from it, I was able to do a nice simple data class:

data class Oauth (var queryStringParameters: Map<String,String>? = null) {
  val code : String
    get() = queryStringParameters?.get("code") ?: ""
}

Thank you everyone for the help!