Reputation: 693
I am trying to make the redirect work in AWS API gateway. I configured the method response to include Location in the header and on the Integration Response, I set the parameter as : Location = integration.response.body.location. however, when I test the API, instead of redirecting me to the location, it just shows me the text for the location on the API page. Has anyone encountered this before?
The string shown is actually the correct location but the API does not redirect me to that URL.
Upvotes: 18
Views: 40760
Reputation: 9836
Inspired by Luke's answer
AWS API Gateway natively supports Velocity (a Java-based template engine) which enables us to dynamically set the redirect URL and even set cookies based on the incoming request (headers, query params, body, etc).
Here is a 302 redirect example without the use of Lambda:
# AWS Console > API Gateway > Create API > REST API > Import > Import from Swagger or Open API 3
openapi: 3.0.1
info:
title: 'API Gateway redirect without Lambda. Powered by API Gateway Mock Integration'
description: 'Accept a query parameters: "url" as the destination (optional), "pid" as the affiliate partner tracking ID cookie value (optional)'
version: ''
paths:
"/redirect":
get:
parameters:
- name: url
in: query
schema:
type: string
- name: pid
in: query
schema:
type: string
responses:
'302':
description: 302 response
headers:
Cache-Control:
schema:
type: string
Set-Cookie:
schema:
type: string
Content-Type:
schema:
type: string
Location:
schema:
type: string
x-amazon-apigateway-integration:
responses:
default:
statusCode: '302'
responseParameters:
method.response.header.Cache-Control: "'no-store, no-cache, must-revalidate'"
method.response.header.Set-Cookie: "''"
method.response.header.Content-Type: "'text/html'"
method.response.header.Location: "''"
responseTemplates:
application/json: >
#*
Velocity (a Java-based template engine) is natively supported by AWS API Gateway
*#
#set($domain = ".example.com")
#set($redirectUrl = $input.params("url"))
#if($redirectUrl != "")
#set($redirectUrl = $util.urlDecode($redirectUrl))
#else
#set($defaultFallbackUrl = "https://www$domain")
#set($redirectUrl = $defaultFallbackUrl)
#end
#set($context.responseOverride.header.Location = $redirectUrl)
#set($trackingCookieValue = $input.params("pid"))
#if($trackingCookieValue != "")
#set($trackingCookieName = "affiliate_partner_id")
#set($maxAge = 60 * 60 * 24 * 30)
#set($context.responseOverride.header.Set-Cookie = "$trackingCookieName=$trackingCookieValue; Max-Age=$maxAge; path=/; domain=$domain")
#end
requestTemplates:
application/json: '{"statusCode":200}'
passthroughBehavior: when_no_templates
type: mock
Appendix: if you need to deploy the API Gateway mock integration via pure CloudFormation, here is my tricky solution:
# Reference: https://cloudkatha.com/api-gateway-custom-domain-using-cloudformation/
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Demo: how to deploy API Gateway via pure CloudFormation'
Resources:
ApiGatewayRestApi:
Type: AWS::ApiGateway::RestApi
Properties:
Body: <% Content of API Gateway OpenAPI YAML %>
ApiGatewayStage:
Type: AWS::ApiGateway::Stage
Properties:
DeploymentId: !Ref ApiGatewayDeployment__CUSTOM_FILE_HASH_PLACEHOLDER__
RestApiId: !Ref ApiGatewayRestApi
StageName: !Ref Env
# ⬇️ Solution B of https://medium.com/@rokaso/aws-cloudformation-terraform-not-deploying-your-api-gateway-changes-cd87d30850cc (Solution C does not work)
ApiGatewayDeployment__CUSTOM_FILE_HASH_PLACEHOLDER__:
Type: AWS::ApiGateway::Deployment
Properties:
RestApiId: !Ref ApiGatewayRestApi
ApiGatewayBasePathMapping:
Type: AWS::ApiGateway::BasePathMapping
Properties:
BasePath: ""
DomainName: <% Your domain name %>
RestApiId: !Ref ApiGatewayRestApi
Stage: !Ref ApiGatewayStage
Upvotes: 1
Reputation: 1840
To redirect some result to other uri using lambda function and api gateway , you have to use
var err = new Error("HandlerDemo.ResponseFound Redirection: Resource found elsewhere");
err.name = result;
context.done(err, {});
in lambda function so context it will forward the error
And on api gateway
`Method Response:>
Add HTTP STATUS as 302
Response Headers for 302
Add Location
For Mapping
Integration Response
Header Mapping
Location integration.response.body.errorType
This will work
credits from this url https://aws.amazon.com/blogs/compute/redirection-in-a-serverless-api-with-aws-lambda-and-amazon-api-gateway/
Upvotes: 0
Reputation: 5996
There is a simpler way for Lambda redirects with API Gateway:
module.exports.handler = (event, context, callback) => Promise.resolve(event)
// .then(doStuffWithTheEventObject)
.then(() => callback(null, {
statusCode: 302,
headers: {
Location: 'https://gohere.com',
},
})) // Success!
.catch(callback); // Fail function with error
This example is from https://blog.rowanudell.com/redirects-in-serverless/
Upvotes: 10
Reputation: 349
It's possible to redirect to a hardcoded URL using API Gateway without using AWS Lambda. Here's the exported OpenAPI 3.0 definition for how this is accomplished:
openapi: "3.0.0"
info:
title: 'TheApiName'
version: ''
paths:
"/":
get:
responses:
"302":
description: "302 response"
headers:
Location:
schema:
type: "string"
content: {}
x-amazon-apigateway-integration:
responses:
default:
statusCode: "302"
responseParameters:
method.response.header.Location: "'https://github.com/lukedemi/adventbot'"
requestTemplates:
application/json: "{\"statusCode\": 200}"
passthroughBehavior: "when_no_match"
type: "mock"
Note that when you import this API template you still need to "Deploy" it, and you need to create a "Stage" when doing so and then associate the API:Stage with a Custom Domain (which requires an ACM cert when first creating the custom domain in API Gateway) and then you can ONLY deploy this single API to the domain since you need to use an empty basepath (which resolves to /
) and that mapping doesn't allow any other /anything
routes due to the way API Gateway works.
Upvotes: 19
Reputation: 656
Here is what I actually used in my Lambda. I let the API well alone. The API collects data sent to it: form data. It is a very simple bit of code that you can do a lot with.
I process the form data in lambda: extract variables, revalidate them, save them into dynamoDB, then issue an email asking the new signup to verify their intentions to satisfy GDPR and make sure I have captured a genuine email address from someone who is capable and interested in interacting and then provide an on-screen response.
The on-screen response is a redirection to a specific thank-you page explaining they need to check their email and click on the link.
All you need to do in the example is swop Amazon.com for your landing page.
By using the variable: redirectURL I can vary the response and use the API and Lambda for a range of different forms on different website pages. I can set the redirect as a hidden form field in the form itself if I want to.
let redirectURL= 'https://amazon.com/';
var response = {
"statusCode": 302,
"headers": {
Location: redirectURL,
}
};
callback(null, response);
Upvotes: 3
Reputation: 1345
Firstly, you want to create a method response for the "location" header. Then you'd like to map the location header value from the response of your Lambda. In Node.js runtime you could map it to integration.response.body.errorType
. This way you'll be able to redirect by doing:
// Returns 302 or 301
var err = new Error("HandlerDemo.ResponseFound Redirection: Resource found elsewhere");
err.name = "http://a-different-uri";
context.done(err, {});
For the full writeup, see: https://aws.amazon.com/blogs/compute/redirection-in-a-serverless-api-with-aws-lambda-and-amazon-api-gateway/
Upvotes: 0
Reputation: 693
Ok, I found the problem. The variable I was storing the location to is defined as a string instead of an object which is why, the web page is showing it as text. It is now redirecting to the page.
Upvotes: 0
Reputation: 2066
Are you sure the API endpoint is returning 302?
Make sure you don't have any 2xx or 3xx response codes other than 302 defined for your method. You can only have one "successful" response code mapping. 2xx and 3xx codes are all considered success codes.
Upvotes: 0