I am trying to get the x-total-count response header from a fetch JS request, I have included Access-Control-Expose-Headers as advised in other previous posts and I am still unable to get the response header, I can see it is being received in chrome dev tools and have tried response.headers.get('x-total-count'); and iterating over response.headers with no luck.
What am I missing here?
async function postData() {
const myPost = {
"listingType":"Sale",
"propertyTypes": [
"townhouse",
"duplex",
"semiDetached",
"studio",
"townhouse",
"villa",
"ApartmentUnitFlat",
"Rural",
"house"
],
"geoWindow": {
"box": {
"topLeft": {
"lat": aNorth,
"lon": aWest
},
"bottomRight": {
"lat": aSouth,
"lon": aEast
}
},
},
"pageNumber": pageNumber,
"pageSize": 100
}
const options = {
method: 'POST',
body: JSON.stringify(myPost),
headers: {
'Content-Type': 'application/json',
"X-API-Key": "API-KEY",
'Access-Control-Expose-Headers': 'x-total-count'
}
};
const response = await fetch('https://api.domain.com.au/v1/listings/residential/_search', options)
if (!response.ok) {
const message = `An error has occured: ${response.status}`;
throw new Error(message);
}
const totalCount = response.headers.get('x-total-count');
for (var pair of response.headers.entries()) { console.log(pair[0]+ ': '+ pair[1]); }
console.log(totalCount)
As an updated I contacted the team that runs this API and received the following response below, turns out it was an issue on their end.
It would appear you've run into an issue with our early support for
CORS requests, the header you are trying to set,
Access-Control-Expose-Headers, is actually one that we specify from
our side.
Presently we don't specify it completely, so the x-total-count header
is not exposed to browsers which follow the CORS rules.
I have added this issue to our backlog to be rectified as soon as
possible, and it will most likely will be part of our first planned
update in early January 2021.
Related
I'm new to cypress, so I apologize if I make no sense here.
i have a cypress script that does a POST request. My end goal is to check API validations. whether API responds with correct error messages for a given JSON body. for that, I want to pass the same JSON body with different values to the cypress request function.
I have my JSON object in a different js file. (channel_query.js)
export const CreateChannel = {
"name": "channe Name",
"tagline": "tasdsadsaest",
"date": "03 Mar 2021",
"time": "2.00 p.m",
"beginsOn": "2021-03-04T13:59:08.700",
"expiresOn": "2021-05-28T14:54:08.700",
"description": "sample Descritptin",
"url": "www.google.com"}
I have my cypress request in the integration folder (channel.js)
import { CreateChannel } from '../queries/channel_query';
it('Create a channel',function() {
cy.request({
method: 'POST',
url: '{my URL}',
body: CreateChannel ,
headers: headers
}).then((response) => {
expect(response.status).to.eq(201)
expect(response.body.name).to.eq(CreateChannel.name)
})
}) })
My question is,
How to make values in JSON object dynamic & then define them in the cypress request function? so I can pass the same JSON to check different validations.
#Mr. Gleb Bahmutov
Help is much appreciated guys!
The simplest way might be to place an array of channels in the JSON file and make the test data-driven.
export const channelData = [
{
"name": "channe Name",
... // plus other properties
},
{
"name": "name2",
... // plus other properties
},
]
The test
import { channelData } from '../queries/channel_query';
describe('Test all channels', () => {
channelData.forEach((channel, index) => {
it(`Testing channel "${channel.name}"`, function() {
cy.request({
method: 'POST',
url: '{my URL}',
body: channel,
headers: headers
}).then((response) => {
expect(response.status).to.eq(201)
expect(response.body.name).to.eq(channel.name)
})
})
})
This question already has answers here:
On Firefox, CORS request gives error ":" (colon)
(4 answers)
Closed 2 years ago.
I have a problem with a fetch on an API, here is my code:
const OPTIONS = {
method: 'GET',
headers: {
'X-Auth-Token': process.env.FOOT_KEY,
}
};
export async function setLeagues() {
const countries = [
{
name: "Ligue 1",
leagues_id: 2015
},
{
name: "Premier League",
leagues_id: 2021,
},
{
name: "Bundesliga 1",
leagues_id: 2002,
},
{
name: "Primera Division",
leagues_id: 2014,
},
]
let allLeagues = [];
for (const country of countries) {
const { name, leagues_id } = country;
const response = await fetch(
`http://api.football-data.org/v2/competitions/${leagues_id}`,
OPTIONS
);
const data = await response.json();
allLeagues.push(data);
}
return {
type: "SET_LEAGUES",
payload: allLeagues
}
}
But I have a console error :
However when I make the request with postman the returned response contains well:
Access-Control-Allow-Origin: *.
Finally the error seems to be present only on firefox but not on chrome.
I try to fetch this API : football-data.org/docs/v2/index.html#_cors_handling, who is CORS enabled.
Thanks you for your help !
this might be more work, but when I had a similar issue this is what I used.
I would recommend using cors-anywhere. Essentially you would host your own version of the service and make your requests using cors-anywhere as a proxy. Cors-anywhere will add the necessary headers and handle cors for you.
https://github.com/Rob--W/cors-anywhere
Also once you have it running, make sure to set you env vars so you only allow traffic coming from your website. I will look something like this: export CORSANYWHERE_WHITELIST=https://example.com
I have the following Typescript function that assumes a Chrome browser has already been launched using Puppeteer. The documentation for the Fetch functions used below can be found here.
async function modify(client: CDPSession) {
client.on('Fetch.requestPaused', async ({ requestId, request, frameId, resourceType, responseErrorReason, responseStatusCode, responseHeaders, networkId }) => {
// Correctly prints out the User-Agent header's value
console.log(request.headers["User-Agent"]);
// After this line is run, I can inspect the request.headers object and see that User-Agent was successfully edited
request.headers['User-Agent'] = 'trying to edit this header';
// Continuing the request gives an error
await client.send('Fetch.continueRequest', {
requestId: requestId,
headers: request.headers,
});
});
}
Here is the specific error I'm seeing:
Error: Protocol error (Fetch.continueRequest): Invalid parameters headers: array expected
How can I resolve this error and successfully modify the request.headers? Is this a silly Javascript/Typescript syntax issue that I just can't figure out?
Fetch.requestPaused returns the headers as an object. e.g.:
{
"Upgrade-Insecure-Requests":"1",
"Accept": "text/html,application/xhtml+xml"}
}
Fetch.continueRequest expects an Array<{name: string, value: string}>. e.g.
[
{"name": "Accept", value: "text/html,application/xhtml+xml"}
]
You can use the code that Puppeteer is using:
function headersArray(headers) {
const result = [];
for (const name in headers) {
if (!Object.is(headers[name], undefined))
result.push({name, value: headers[name] + ''});
}
return result;
}
I am using react-adminframework, and I have written my own DataProvider. I am trying to accomplish that when an User is created, an instance of UserPossession is created as well. My code bellow accomplishes that, but react-admin Front-end just displays the warning message:
Failed to execute 'fetch' on 'Window': Request with GET/HEAD method cannot have body
I checked the Network tab in Developer Tools and every request to server is correct, there is no error. Which leaves me confused and stuck with this, because I have no idea what that warning means or why is it even occuring.
My code is a part of convertDataRequestToHTTP constant and looks like this:
if (resource === 'User') {
url = `${apiUrl}/${resource}`;
options.body = params.data;
httpClient(url, {
method: 'POST',
body: JSON.stringify(options.body),
})
.then(response => (
url = `${apiUrl}/Location`,
options.method = 'POST',
options.body = JSON.stringify({
"odata.type": "HardwareDatabase.UserPossession",
"Name": response.json.Login,
"UserId": response.json.Id
}),
httpClient(url, {
method: options.method,
body: options.body
})
));
}
If you have any questions regarding the code I can clarify.
Thank you for any ideas in advance.
Since you are stating that this code snippet is a part of convertDataRequestToHTTP I might see the issue. httpClient cannot be used in this constant since it creates duplicit calls to API or in your case, this Warning. Correct way would be to only state the options constant.
url = `${apiUrl}/${resource}`;
options.body = JSON.stringifiy(params.data);
options.method = 'POST';
Later in the constant that converts response from OData to mandatory React Admin format, state the httpClient.
params.data = {
"odata.type": "HardwareDatabase.UserPossession",
"Name": response.json.Login,
"UserId": response.json.Id
};
httpClient(`${apiUrl}/Location`, {
method: 'POST',
body: JSON.stringify(params.data),
})
Unfortunately, the GET method for XMLHttpRequest and fetch don't support request bodies.
A temporary work around I found was to use the axios library, which does let you send GET with request bodies.
const res = await axios.get("/api/devices", {
data: { deviceName: 'name' }
})
I have a working API written in C# that return something like this:
status: 200,
ok: true,
statusText: "OK",
url: "http://localhost:53619/api/EventList/All"
_body: "[
{
"id":"6eb057be-1c27-4d92-83cc-95216dc1b21b",
"user":{"id":"mail#mail.org",
"firstname":"name",
"lastname":"lastname",
"email":"mail#mail.com",
"avatar_url":"string"},
"project":
{ "id":0,
"name":"super project",
"description":"woop woop",
"created":"2016-09-15T10:09:17.425Z",
"autodesk_client_id":"123456",
"autodesk_client_secret":"123"},
"title":"Jan lagde et super prosjekt",
"content":"test",
"icon":"string",
"type":"string",
"properties":"string",
"datetime":"2016-09-15T12:16:56.6826078+02:00"}
]
This is the default response from the C# API. HTTP status code, url, message etc. Then there is a variable _body containing the json data I actually need.
Then in Angular 2 I have the following to get the data:
get(data: User): Promise<Event[]> {
let body = JSON.stringify(data);
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this._http
.post(this.apiUrl + '/All', body, options)
.toPromise()
.then(res => {
console.log(res);
return res._body.json(); <--------- ERROR (_body not defined)
})
.catch(this.handleError);
}
This works well, I get all the data and it's printed out in the console.
But Angular refuse to accept that the Response contain the variable _body and crash!
How can I fix this?
Thanks
you should use return res.json()._body;