503 error when fetching an internal NextJS api with query parameters on AWS Amplify - amazon-web-services

I am trying to fetch data from a JSON file through NextJS internal API on the client side. But it is always throwing 503 error:
The Lambda function associated with the CloudFront distribution is invalid or doesn't have the required permissions.
We can't connect to the server for this app or website at this time. There might be too much traffic or a configuration error. Try again later, or contact the app or website owner.
I tried to use the GET method with query params in the URL, but it didn't work, then I try the POST method with the query in the body(just to test out), but it also didn't work either.
Here is the code:
const response = await fetch(`/api/search?q=${query}`, {
method: "GET",
headers: {
'Content-Type': 'application/json',
},
})
const res = await response.json()
I have another component that sends some user inputs to save in my DB, and it is working perfectly. (I am really confused why one works but not other given both are equivalent request)
Also, the same app deployed on Vercel is working perfectly. So I think the issue is with Amplify.
Anyone had similar issues with the Next app on Amplify? please help.

most likely you are sending a GET request but you have something in the body. e.g. form-data. this is example in postman.

Related

Cannot query AWS API Gateway using API Key and CORs

I'm almost complete with a new web app, however, I'm getting a 403 error from AWS's API Gateway due to a CORs issue.
I'm creating a Vue app and using Vue's axios library. CORs is enabled and the request works with API Key Required option turned off in AWS's API Gateway by sending the following:
axios
.get('My-URL-Endpoint',{headers: {})
.then(response => (this.passports = response.data ));
When I turn on API Key Required functionality inside AWS's API Gateway. It works when I use Postman along with including x-api-key: My-API-Key. However, using Vue's axios it does not work and returns error 403:
axios
.get('My-URL-Endpoint', {headers: {
'x-api-key': 'My-API-Key'
}})
.then(response => (this.passports = response.data ));
My first instinct is that the problem is related to how Axios is sending the request through the browser. From what I can gather it looks like the pre-flight check is failing because I am receiving the following error within the browser:
Access to XMLHttpRequest at 'My-URL' from origin 'http://localhost:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Sure enough it looks like there is no access-control-allow-origin key in the response. So I added access-control-allow-origin to the response of the 403 message and got a new error "It does not have HTTP ok status"
I've been trying nearly everything to get this to work! I came across stackoverflow answer where it seems like the person was suggesting that API Key Required Key functionality can't work with CORs. This kind of seemed like that cannot be true. It would be a pretty crippling restriction.
So my question is how to get the browser's pre-flight check to work along with CORs and API Key capability inside AWS's API Gateway?
Thank you!
If you have enabled cors on your api gateway, the next place to look is the application code such as lambda. Make sure the Lambda is returning the correct cross origin headers in both successful and failure scenarios.
First of all you can check if the request is reaching the lambda from the cloud watch logs. Another way to check this is to temporarily point the Api gateway target to the Mock end point.
If the mock endpoint works, then the problem is the application code. otherwise the problem is in your api gateway end point.
Also note that any headers you use should be white listed in the Access-Control-Allow-headers section when you enable to cors for your method/resource.

AWS API Gateway returning different status via Postman to Method Test

I have an AWS Lambda integrated into API Gateway. The lambda is current just returning an error:
exports.handler = (event, context, callback) => {
context.fail(JSON.stringify({
status: 500,
errors: 'This is definitely the same endpoint.'
}));
};
I have added an HTTP status 500 response in method response of API Gateway, and I have mapped an integration response using regex *"status":500.* to the 500 response.
When I test this using the Method Test functionality in AWS, I get the 500 response I expect:
But when send command to the endpoint with Postman, I get a 200 status:
How can this be? The Method Test seems to suggest my Integration Response and Method Response setups are correct, and I have my regex set up correctly, but what am I missing between the API Gateway and the rest of the world that would produce this different result?
Have you tried Deploying the API? Maybe a redeployment might fix the issues.
did you stumble across the Handle Custom Lambda Errors in API Gateway guide already?
The format suggested there is:
{
"isBase64Encoded" : "boolean",
"statusCode": "number",
"headers": { ... },
"body": "JSON string"
}
So you basically need to return this JSON structure. I check this with AWS serverless express library (line 100-105) - which we use - and it's returning this structure.
The major challenge is, that sending the HTTP response to the client is a task for the API Gateway and to do so, you must return a valid JSON response from the lambda in a format that the API gateway unterstands. The execution status of the lambda will be also 200 (because it worked A-Okay) but the API Gateway will transform your response into a 500. This is also why you nedd this double/triple JSON encoding (JSON-as-string in JSON-attributes).

How do you add JSON data to an HTML AWS lambda response body?

I've run into some trouble with a site I am building. It used AWS lambda functions. I am building and deploying on AWS CodeStar.
The site strips the URL parameter (e.g. /BTC), sends that to external API endpoint, which returns some JSON data. I can display the entire JSON response using body: JSON.stringify(response), so it is definitely coming through from the API. However, I would like to the JSON values to HTML markup before sending back to the client. Yet, when I do something like var html = '<h1>JSON.stringify(response['DISPLAY']['BTC']['USD']['MARKET'])</h1>';. I receive an Internal Server Error - Malformed Request.
I can't figure this out. I'm fairly new to the world of AWS, so may be overlooking something, I've looked around in the docs and can't seem to find anything related to this.
Also, when I had the JSON.stringify output displaying on the webpage. If I re-parsed this in the browser console, response['DISPLAY']['BTC']['USD']['MARKET'] returned a value - so I am fairly sure the syntax for the payload data is correct.
exports.get = function(event, context) {
var ticker = event.pathParameters.currency;
rp(`https://min-api.cryptocompare.com/data/pricemultifull?fsyms=${ticker}&tsyms=USD`)
.then(function (response) {
var html = `<h1>${JSON.stringify(response['DISPLAY']['BTC']['USD']['MARKET'])}</h1>`;
context.succeed({
statusCode: 200,
body: html,
headers: {'Content-Type': 'text/html'}
});
})
.catch(function (err) {
console.log('error: ', err);
});
};
Any help would be appreciated! Happy to provide more info if required.
This is caused by a combination of a couple of things, as far as I can tell:
Within your .catch block you are not calling context.error. In other words, if there's an error in your lambda function, the lambda function never signals that it's finished executing properly to the invoker. API gateway throws up its hands in despair and spits out a 502 error.
response is a string, so when you try to access its properties, you cause an exception and end up in your .catch block. First you need to JSON.parse(response)
Here's a helpful note: whenever you call console.log, the log output can be found in CloudWatch > Logs > /aws/lambda/<your-lambda-name>. This can be useful for figuring out why/where things are breaking.

Elastic Beanstalk doesn't accept headers from Axios

I am making a React Native App with a Lumen API as the backend. I want to protect all my routes with a simple middleware. I have modified the AuthServiceProvider to check whether the request has a header with the token, if it does check whether that token belongs to a user.
AuthServiceProvider
$this->app['auth']->viaRequest('api', function ($request) {
if($request->header('access_token')){
return User::where('access_token', $request->header('access_token'))->first();
}
return null;
});
A simple Axios request would look like this,
axios.get('url/to/site', {headers:{access_token: '12345667890ABC'}})
.then(res => console.log(res))
.catch(err => err.response);
The routes are placed inside the auth middleware in web.php file. I know that while working with mobile Apps we don't have to worry about CORS, so that isn't the problem.
Strangely enough the code seems to work on my localhost and authenticates the user, however when I deploy to AWS ElasticBeanstalk it returns unauthorized. I am using the free tier of AWS for now. My instance is running Amazon Linux AMI
I have also tried setting the axios headers as such;
axios.defaults.headers.common['access_token'] = '12345667890ABC';
And just for peace of mind I added some additional headers via another middleware in Lumen as well.
return $next($request)
->header('Access-Control-Allow-Origin', '*')
->header('Access-Control-Allow-Headers', 'access_token')
->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
I have tested local and AWS routes from Postman as well, both with and without the access_token. The result is the same, it works for localhost but does not work for AWS, where the header access_token is just missing.
At first I thought the problem might be a config or permission issue on AWS but I have also tried the whole process on a simple shared hosting account and the middleware still does not authenticate the request via Postman.
Remove underscores from the header variables, example:- header_var_val = "some value" replace it with --> headervarval = "some value"

Calling RESTful API Using Python on Google App Engine

I got some problems when calling RESTful webservice.
I'm running a Django 1.5 project on google app engine now.
And I make use of httplib in python to call a RESTful webservice.
All methods(PUT, GET, DELETE, POST) work well on my local Machine (python 2.7.5, Django 1.5).
However, the behavior is changed on GAE...
PUT (used to store the data which user edited his information on the sites.), POST method is work well.
The GET method sometimes can't get the latest results from webservice server (not google datastore, the data are stored in other database server, I use the GET method to fetch the data from that server).
The DELETE method is not working totally on GAE.
Here is my code:
import httplib
args = ""
headers = {"Accept":"application/json"}
conn = httplib.HTTPConnection(IP, 8080)
try:
conn.request("DELETE", Some_API_Method_Url, args, headers)
response = conn.getresponse()
res = response.read()
I can't figure out why this happened, hoping someone can help me :(
Thanks in advance!
UPDATED:
I just found why the DELETE method is not working based on this link.
I send an ajax request which type is delete in my js file to my Django backend with the following code:
$.ajax({
type:'DELETE',
url:'some_url',
data:JSON.stringify({'key':'value'}),
contentType: 'application/json; charset=utf-8',
dataType: "text",
success: function(data){...},
error: function(data){...}
});
It seems that the appspot doesn't allow the DELETE request with body(data).
so, I changed the type of the AJAX request to POST, and it works...