I've come across this problem a few times now and I feel like there's someone out there who knows a better way to troubleshoot api calls than i - specifically request headers.
Often when i need to pass my api token via a request header, I am constantly groping at the exact format to pass my key's (it seems there's not a universal format for doing this).
For example, I am currently trying to access the vultr v1 api. The docs give a curl example where API-Key: SOMEKEY needs to be passed, yet, my first attempt rarely works then i'm just groping... Do they want my key in a key/value pair or a single string in an array? Do i use es6 objects (without quotes) or not.
here's what i mean:
// one method
const opts = {
headers: {
API-Key: 'SOMEKEY'
}
}
// another
const opts = {
'headers': {
'API-Key': 'SOMEKEY'
}
}
// another
const opts = {
headers: [
'API-Key: SOMEKEY'
]
}
axios.get(url, opts).then(res => console.log(res.data))
which is the proper way? In the curl example given by vultr it shows:
curl -H 'API-Key: EXAMPLE' https://api.vultr.com/v1/iso/list
I also see in my network inspector that the request headers show i am passing my API key yet i am still getting a 403 (bad key error)
I have double checked the validity of my key and that's not the problem.
My question is this:
How do i find the correct format for the headers? Is there a better troubleshooting method for this kind of problem? Any help would be greatly appreciated. Thanks ya'll
UPDATE:
Turns out they've got access control based on IP's. I hadn't noticed it till just now. They were blocking my request because of this. My question still stands however. Good methods for figuring out correct formats? Is there a correct format?
One way is setting Headers while creating axios object, as follows :
axios = axios.create({headers: {'API-Key': 'EXAMPLE'}});
axios.get(url, opts).then(res => console.log(res.data))
Or
axios.get(url, {headers: {'API-Key': 'EXAMPLE'}}).then(res => console.log(res.data))
Related
I've created a client-side application that makes an API call. The issue with this, however, is that in order to make the API call, I have to use an API Key. If I make the call client-side, the user will be able to see the API key. How do I avoid this? Well, if the answer is to call the API server-side, how do I do that? There seems to be little information wherever I look regarding server-side programming, and if anyone could lead me in the right way, it would be great.
You have to set it in the header with bearer
let config = {
headers: {
'Authorization': 'Bearer ' + KEY
}
};
Axios.get('http://url', {}, config )
.then( (response) => {
console.log(response)
})
.catch();
I have a small Api built in laravel that is supposed to return a response when an endpoint is hit.
The problem is, that same end point returns something in postman but returns empty data in Vue Js.
I have been battling this for 48 hours now, and is driving me insane, any help will be appreciated.
Thank you
public function search_passport(Request $request){
$pass = DB::table('passengers')->where('passport_number',$request->input('passport_number'))->get();
if($pass->count() == 0){
return response(['message' => 'Passport number not found, please fill the form']);
}
return new PassengerResource($pass);
}// search_passenger
Above is the code from the controller in the Api
Route::post('/searchpassport', [PassengerController::class, 'search_passport']);
And this is the route
this.$http.post('searchpassport', this.passport_number, {headers:{
'Authorization' : 'Bearer ' + this.token.access_token,
'Accept' : 'application/json',
'Content-Type' : 'application'
}})
.then(res => {
console.log(res)
})
This is also the API call am making in the Vue Js
Assuming this.$http is Axios and this.passport_number is a string, you're missing the field / property name for the request payload, ie "passport_number". Also, your Content-type header is incorrect.
Try this instead
this.$http.post("/searchpassport", {
passport_number: this.passport_number
}, {
headers: {
Authorization: `Bearer ${this.token.access_token}`
}
})
You do not need to supply the Accept or Content-type headers. The defaults will be sufficient.
It's good practice to use your browser's developer tools for debugging. The Network tab in particular is great for checking the headers and data sent in your HTTP requests and the responses you get back.
Good Day All,
I'm trying to do a POST request using the puppeteer headless chrome library. I can't seem to get the below code to work.
// Get csrf token
let token = await page.evaluate(() => document.querySelector('[name="CSRFToken"]').value);
let postResponse = await page.evaluate(async(token, cookies) => {
let response = fetch("/loyalty/points", {
method : 'POST',
cookie : cookies,
postData : 'CSRFToken=' + token,
}).then(response => response.text()).catch(error => console.log(error));
return response;
});
console.log('Final response');
console.log(postResponse);
I keep on getting an error that the CSRF token has not been set or that the cookie is invalid.
My question is, am I using the correct method in puppeteer to do a POST? If so, is there any way for me to do some debugging that I can see the actual POST request that was sent?
I appreciate any advice or help. Thanks
You are not creating a request body: hence the error. The postData attribute you set on the request object is not any known attribute, so it won't be set on the request either, meaning that the server will never see your CSRF token. You should look into the MDN docs on fetch().
I believe you should be all good by simply replacing postData with body, but it's hard to know without access to your endpoint. For all we know it might require special headers.
Given that you only post normal form data (which is implied by your key=value code), I would also start using the FormData objects provided by your browser to avoid manual coding of implementation details.
const formData = new FormData();
formData.append("CSRFToken", token);
const response = fetch("/loyalty/points", {
method : 'POST',
cookie : cookies,
body : formData,
headers : {
'cookie' : cookies,
/* other headers you need, possibly content-type (see below) */
},
}).then(response => response.text()).catch(error => console.log(error));
return response;
});
Caveat: using the FormData API will always set the content-type of the data to multipart/form-data. If your server for some reason doesn't support that encoding, and you need to use application/x-www-form-urlencoded (see here for difference),
you can't blindly change the Content-Type: you also need to url encode the content.
For debugging I would simply use a normal Chrome instance to see this. You should be able to run the code there and see the network requests in DevTools (where it would be immediately noticeable that you POST an empty request).
I recently restructured my API on AWS Gateway to make all my Lambda functions use proxy integration - before that, every single parameter was passed in as a path parameter (awful, I know.)
I never had any issues with CORS then, and I've tried several things over the past few hours to fix the issue discussed in the topic line.
First, I used a proxy resource and used an "ANY" method, but when that gave me CORS issues, I enabled CORS on the API method and tried again - still nothing. So, I tried changing it so that it was a "POST" request instead and enabling CORS - still nothing. And I made sure to deploy after every setting change. Then, I got rid of the proxy and instead just made a "POST" method with CORS enabled, and still nothing.
I'm using Angular's http post method.
Edit:
I'm using Angular 1.6.4, and this is the code I'm using to call the API:
this.checkRegistered = function(email){
var data = { Email : email};
var toSend = JSON.stringify(data);
return $http.post('link', toSend);
};
That's in my service for the angular module, and it's being called from this function in the controller:
function CheckIsRegistered(email)
{
return userService.checkRegistered(email).then(function(res){
if (res.data.statusCode === 200){
return res.data.body;
}});
}
I've configured all the parameters so that "Email" is what it should be expecting, and I did replace the word 'link' with the actual link.
When I enable CORS through the console, I assign the headers as follows:
Access-Control-Allow-Headers: 'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'
Access-Control-Allow-Origin: '*'
This is especially infuriating because I've actually worked with this exact issue before and solved it fairly easily, but now that I'm using Lambda's proxy integration I've run into this issue again and I can't quite seem to figure it out.
Any help is appreciated.
I figured out the problem - I had to add the headers for CORS to the Lambda response. Here's the code snippet for anyone else having similar problems:
connection.query('arbitrary query', [params], function (error, results, field) {
if (!error)
{
connection.end();
var responseBody = results;
response = { statusCode: 200,
headers: { "Access-Control-Allow-Headers": "Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token", "Access-Control-Allow-Origin": "*"},
body: JSON.stringify(responseBody)};
callback(null, response);
}
I put the querying line in there just for context of what "response" is.
I am building a simple web app using ReactJS and create-react-app.
I have a backend API set up on Heroku where I can make POST requests. Everything works fine, except:
When I make a POST request using fetch API, the response is 100% correct but it only gives me 2 standard headers. I want to get my custom header. I have added expose header in my response and here's the plot twist: When I view the headers from Chrome Inspection Tool or Postman (API tool), it shows all the headers, including my custom one. Here is the fetch code I'm using -
fetch(theUrl, {
method: 'POST',
body: JSON.stringify({
"placeholder": "placeholder"
})
})
.then(function(res) {
console.log(res.headers.get('CUSTOM_HEADER_NAME'));
})
If it makes any difference, this fetch method is called from a function outside the main body of the ReactJS component.
The name of the custom header is Image-Identification-Path, and the header in my response header is Access-Control-Expose-Headers for Image-Identification-Path.
Summary: How do I get my custom header using fetch?
You must configure the server to which the request is sent, such that its response has an Access-Control-Expose-Headers header that has the name of your custom response header.
Otherwise, if your browser doesn’t see the name of your custom header in that Access-Control-Expose-Headers header, it won’t let you access the value of your custom header.
In such a case it’s expected that you’d still be able to see the custom header if you look at the response in Postman or even in your browser devtools.
But just because the browser gets the custom header in the response doesn’t mean the browser will expose it to your frontend JavaScript code.
For cross-origin requests, browsers will only expose that custom response header to your frontend code if that header name is in the Access-Control-Expose-Headers value.
I know this question is old but I ran into this problem yesterday, and the given answer didn't work for me.
The solution I found was given in this article. Basically:
You can’t directly access the headers on the response to a fetch call - you have to iterate through after using the entries() method on the headers.
So, in your particular case you should be able to achieve the goal by using this code:
fetch(theUrl, {
method: 'POST',
body: JSON.stringify({
"placeholder": "placeholder"
})
})
.then(response => {
for (var pair of response.headers.entries()) { // accessing the entries
if (pair[0] === 'CUSTOM_HEADER_NAME') { // key you're looking for, in your case Image-Identification-Path
let imagePath = pair[1]; //// saving that value
}
}
.... })