Cannot get AWS API Gateway to override response codes - FitBit endpoint verification - amazon-web-services

I am integrating FitBit with my company's platform and we are switching over from syncing with our own server to sending the data to an AWS Kinesis stream. This requires us to also set up an AWS API Gateway with a POST method to write the data to the stream. I've also set up a GET method on the same resource for the verification process.
Here's the problem I'm facing:
Once I have the API Endpoint properly set up, FitBit provides a verification code and requires a verification process in which it sends a GET request to the endpoint with a ?verify={correctVerificaitonCode} query param and wants a 204 response, and one with a ?verify={incorrectVericationCode} param and wants a 404 response. This would obviously be easy for me to accomplish in our Rails backend, where I'm in control of the code, but on AWS it's a tangled mess with little control.
I have read endless documentation on AWS about Mapping Templates and Integration Response, but no matter what I do, I cannot get the API to respond with anything other than a 200 (when the request is clean and has any ?verify param) or 500 (when I purposefully make a bad request). There is no straightforward answer in the AWS docs about this.
This is the closest I have come to a setup that the docs promise should work, yet it does not:
Using the Integration Response HTTP Status Regex
And with this mapping template
I'm two days in on this and frustrated to my wits' end. Help!

Just in case anyone find this thread in the future and is struggling with the same issue - here is how you verify a FitBit Developer API app with an Amazon Kinesis stream being fed by an AWS API Gateway:
First, set up the POST method of your API - there are AWS guides to this. Select AWS service as the integration type and kinesis as the service, then set up a mapping template for 'application/json' to look like this:
#set($event = $input.body)
#set($data = '{"action":' + $event +', "authorization": "' + $input.params('Authorization') + '", "stage":"' + $context.stage + '"}')
#set($body = $util.base64Encode($data))
{
"Data": "$body",
"PartitionKey": "shard-1",
"StreamName": "gm-fitbit"
}
Once you've done that, create a GET method on the same resource. Set MOCK as the integration type and create the endpoint. Now click on the GET method and visit Method Request. Expand URL Query String Parameters and add verify as a query param. Now, go back to the method and visit Integration Response.
Under the already existing 200 response method, expand it and add an HTTP status regex of 2\d{2} and passthrough handling.
Expand Mapping Templates, and for 'application/json' create this mapping template:
{
#if( $input.params('verify') == "theVerificationCodeProvidedToYouByFitbit" )
#set($context.responseOverride.status = 204)
#else
#set($context.responseOverride.status = 404)
#end
}
That's it! Deploy the API again, head back to Fitbit, and click verify!
There. Now there is officially a guide online to integrating Fitbit with an AWS Kinesis stream, the one I wish I had when struggling with this for 3 days.
Cheers!

Related

How to set the api version being called in API Gateway when integrating with AWS Service CloudWatch?

I get the following error message when calling actions for CloudWatch in API Gateway.
"Error": {
"Code": "InvalidAction",
"Message": "Could not find operation DescribeAlarms for version 2009-05-15",
"Type": "Sender"
}
I've been using DescribeAlarms for testing. My setup is as follows.
Integration Type = AWS Service
AWS Service = CloudWatch
HTTP method = POST
Action = DescribeAlarms
The error references the API Version 2009-05-15, which only has ListMetrics and GetMetricStatistics according to it's documentation on page 54. ListMetrics does indeed work as expected with my setup.
The current version is 2010-08-01 but I don't see anyway to reference that in API Gateway. In an example of a POST request in the documentation it shows a header labeled x-amz-target with a value of GraniteServiceVersion20100801.API_Name.
My interpretation is I can put Name = x-amz-target and value 'GraniteServiceVersion20100801.DescribeAlarms' in my http header for the Integration Request in API Gateway.
This doesn't change the response and gives the same error message.
I also used the --debug in CLI when calling describe-alarms, and in the body it shows...
"body": {
"Action":"DescribeAlarms",
"Version":"2010-08-01"
}
So I also set http headers to include Content-Type with a value of 'application/x-amz-json-1.1' and then put in
{
"Action":"DescribeAlarms",
"Version":"2010-08-01"
}
but nothing changed with that either.
Any help or guidance would be greatly appreciated.
Under Method Integration -> URL Query String Parameters
I added Version as the Name and '2010-08-01' under Mapped From.
All actions are now working as expected.
I'm trying to PutMetrics directly from Api Gateway -> Cloudwatch using PutMetricData, Version in the query string params didn't work for me.
These 3 HTTP headers in the Integration Request solved it for me:
Content-Type 'application/json'
X-Amz-Target 'GraniteServiceVersion20100801.PutMetricData'
Content-Encoding 'amz-1.0'

Geolocation service with AWS API Gateway and Lambda

What we are trying to do
We are trying to set up a very simple Geolocation service with API Gateway and Lambda.
Very similar to https://ipstack.com/, but we don't want to use an external service as we believe it could be an issue in some jurisdictions to send a non-anonymized IP address to a service we don't control (before getting the user's consent).
Would like to have a simple api https://location.my-site.com that returns the country (for GDPR, cookies, etc purposes).
Now it seems that there is a light Cloudfront behind API Gateway that would produce the header "Cloudfront-Viewer-Country", which would be very simple and achieve what we need. i.e. lambda receives Cloudfront-Viewer-Country and just sends it back.
What we have tried
I have seen solutions such as this one: Build a Geolocation API using AWS Lambda and MaxMind, but I struggle to see why deploying an RDS and maintaining the MaxMind database would make sense for us, if it is already available from Cloudfront-Viewer-Country.
I have seen this question: Accessing cloudfront-viewer-country header in AWS API Gateway using HTTP Proxy?, and tried implementing the answer from Michael - sqlbot. But I cannot seem to access the headers.
I have also tried what is suggested in this post, but I can't seem to access the value of Cloudfront-Viewer-Country either.
What we are doing (in conjunction with 'What we have tried')
To access and check if the header is available I am using the following python lambda function
import json
def lambda_handler(event, context):
response = {
'status': '200',
'statusDescription': 'Found',
'headers': {
'location' : [ {
'event': json.dumps(event)
} ]
}
}
return response
What the problem is
but the event json dump doesn't contain Cloudfront-Viewer-Country.
I suspect I'm doing something wrong but I really can't figure it out. Any pointer would be very much appreciated.
Thank you
I was able to get access to Cloudfront-Viewer-Country by setting a Endpoint Type = Edge optimized.
I could not get it to work with Endpoint Type = Regional or with http api gateway.

Autodesk Data Management API 403-Error

I am trying to receive data via Autodesk Data Management API. So far I've created an Forge-App and connected it with a BIM360 Integration.
Then I wanted to get a list of all hubs, but when I do so, I receive an JSON-Object which contains a warning:
warnings: [{
"AboutLink":null,
"Detail":""You don't have permission to access this API",
"ErrorCode": "BIM360DM_ERROR",
"HttpStatusCode": "403",
...
}]
I called the webservice via AJAX wich looks like that:
this.getToken(function(token) {
$.ajax({
url: "https://developer.api.autodesk.com/project/v1/hubs",
beforeSend: function(xhr) {
xhr.setRequestHeader("Authorization", "Bearer "+token);
}
}).done(...);
The token is a 3-legged one. I am not sure which API I do not have permission for because I am pretty sure, that I have permission for BIM360.(I created the Integration as an administrator).
In addition to was ZHong mentioned, I would suggest you try this sample. It will ask you to provision your Forge Client ID under your BIM 360 settings, just follow the steps that the app will present.
On both 2- or 3-legged, the app accessing the data (Forge Client ID) needs authorization from the account admin. Without that, the Hubs endpoint will not return your BIM 360 hub, and inside that, the sample applies for Projects endpoint.
Does everything else work fine? For example, can you get all the hubs successfully? I just verified on my side, and I can see the response including the same warning as you mentioned, but the hubs are listed correctly, and you can get the projects/items/versions without problem. I pasted my postman response as follow.
If you check the blog https://forge.autodesk.com/blog/tutorial-using-curl-3-legged-authentication-bim-360-docs-upload, it also has the same warning, but seems no impact to the following operation. I am not exactly sure what the warning means, l will check and update the details, but so far, it seems you can ignore it for now.

API Gateway - Get StatusCode

This should have been such a simple issue and I don't understand why it hasn't come up through all my searching (maybe it's just been a long day).
I have an API Gateway API setup, and I am adding a Body Mapping Template to my Integration Response for a 400* error group: see image -
All I would like to get is the StatusCode of the current response (as this is a 400* group - e.g. 401 / 403 / 404 etc.)
The closest I came was through this site: AWS help documentation and I thought I would be able to use something like $context.statusCode - but no luck.
Am I going crazy, or is this just not something required often?
PS - Making changes to any Lambda functions being called, is not an option.
Thanks
There's currently no mapping template variable in API Gateway dedicated to the integration response status code.
We will certainly add this as a feature request.
At current time you are limited to hardcoding the status code value in your response templates. You would either need to define generic status codes (i.e "4XX") or define integration responses for every status code you want to capture. While this seems tedious, this could be managed relatively easily in a Swagger template.
At current time the only way to see the integration response status code is via CloudWatch Logs.
Thanks,
Ryan / Amazon API Gateway
If you are sending error codes from your server then you can easily map them.
I have done something similar but I have used different trick to do. I used to send my own error entities and codes from server.
You have to map those error entities and error codes coming from server to the response that comes from amazon servers. I will try and explain what I mean by this. Api Gateway doesn't send response coming from your own server to the client automatically. You have to map those responses. For example, map 200 as a SUCESS and response entity will be default, that is whatever coming from server.
Now, we default success response is managed but what about error codes and error entities. You have to map them manually.
There are two ways you can do this,
One is manual, go to your api. Create error entities or models. Map them manually for each response code.
This one uses swaggger,
Solution is to import swagger specification of error entities. Add response templates to the swagger specification and let amazon do their job.
I can help you more with swagger. It depends how you are setting up your api on amazon.
Visit this for amazon extenstions to swagger,
http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-swagger-extensions.html#api-gateway-swagger-extensions-integration-response

Handle Space in AWS API Gateway API URL - I am using Dynamodb Proxy

I have a AWS API Gateway - and using dynamodb to read Data from database, its running good enough if I sent a parameter without Space.
URL Pattern: API_LINK/benchmark_performance/{benchmark}
if {benchmark} is replaced with a String with a space - AWS replies with no/blank data, No Error Reported. if the parameter doesn't have space in it then it sends data correctly. I also tried using JS URI_encoder method and send it but same result
If I test the AWS API End point from AWS console (parameter has Space), then the result is shown properly but the same URL gives no data when called from Browser or angular 2 Application.
Question: What should I do at AWS API Gateway Integration Mapping, that it gives me proper output and handles the space in parameter issue.
Got the answer : http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html
I used :
$util.urlDecode() (Decodes an "application/x-www-form-urlencoded" string).
how to use =>
$util.urlDecode($.input.params('yourParameterName'))
in Integration Mapping (section) of API Gateway