POST request works with AJAX but not with fetch - ajax

I need to make a post call to get a token. I wanted to use fetch but I keep getting a 500 error. (jquery ajax request worked fine, but I am using react and I want to avoid installing jquery just for this). What is the difference here?
AJAX (works fine, I get a token back)
var settings = {
"async": false,
"crossDomain": true,
"url": "https://api.com/oauth2/token",
"method": "POST",
"headers": {
"Accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded",
"cache-control": "no-cache",
"Postman-Token": "postmantoken"
},
"data": {
"client_id": clientId,
"client_secret": clientSecret,
"grant_type": "password",
"username": username,
"password": password,
}
}
$.ajax(settings).done(function (response) {
aTkn = response.access_token;
});
return aTkn;
Fetch: get a 500 error : {error: "invalid_request", error_description: "Object reference not set to an instance of an object."} error: "invalid_request" error_description: "Object reference not set to an instance of an object."
fetch("https://api.com/oauth2/token", {
crossDomain:true,
method: 'post',
headers: { "Accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded",
"cache-control": "no-cache",
"Postman-Token": postmantoken},
body:{
"client_id": clientId,
"client_secret": clientSecreet,
"grant_type": "password",
"username": username,
"password": password,
}
}).then((data)=>{debugger})

The data you are passing to fetch must be stringified, otherwise something like [object Object] will be passed in:
fetch("https://api.com/oauth2/token", {
crossDomain: true,
method: 'post',
headers: {
"Accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded",
"cache-control": "no-cache",
"Postman-Token": postmantoken
},
body: JSON.stringify({
"client_id": clientId,
"client_secret": clientSecreet,
"grant_type": "password",
"username": username,
"password": password,
})
}).then((data) => { debugger })
Hope this helps!

Related

API Call from Nuxt3 SSR application to Strapi4 API endpoint shows servers host and not the requests host in header

I am sending a request from a Nuxt3 SSR app (test.example.com) to a custom strapi endpoint (test-backend.example.com)
I'm making the call from Nuxt3 like this from app.vue
<script setup>
import { useStore } from '#/stores/index'
let data = reactive({})
[data] = await Promise.all([
useFetch(`${useRuntimeConfig().API_URL}api/debug`),
])
store.setApiData(data.data)
</script>
To hit this custom strapi endpoint at /api/debug
module.exports = {
async debug(ctx, next) {
ctx.body = {
ctx: ctx,
reqOrigin: ctx.request.origin,
}
}
};
Reading the request headers using ctx.request.origin returns the backend host and not the frontend host.
"ctx": {
"request": {
"method": "GET",
"url": "/api/debug",
"header": {
"host": "test-backend.example.com",
"x-real-ip": "203.96.140.24",
"x-forwarded-for": "203.96.140.24",
"connection": "close",
"cache-control": "no-cache",
"postman-token": "946f9d5f-b9b6-4dc0-a52b-95fd84b81de8",
"user-agent": "PostmanRuntime/7.6.0",
"accept": "*/*",
"accept-encoding": "gzip, deflate"
}
},
"response": {
"status": 200,
"message": "OK",
"header": {
"content-security-policy": "connect-src 'self' https:;img-src 'self' data: blob:;media-src 'self' data: blob:;default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline'",
"x-dns-prefetch-control": "off",
"expect-ct": "max-age=0",
"x-frame-options": "SAMEORIGIN",
"strict-transport-security": "max-age=31536000; includeSubDomains",
"x-download-options": "noopen",
"x-content-type-options": "nosniff",
"x-permitted-cross-domain-policies": "none",
"referrer-policy": "no-referrer",
"vary": "Origin",
"content-type": "application/json; charset=utf-8",
"x-powered-by": "Strapi <strapi.io>"
}
},
"app": {
"subdomainOffset": 2,
"proxy": false,
"env": "production"
},
"originalUrl": "/api/debug",
"req": "<original node req>",
"res": "<original node res>",
"socket": "<original node socket>"
},
"reqOrigin": "http://test-backend.example.com"
Logging ctx on the backend shows that ctx.request.header.host is test-backend.example.com. I was expecting host to be text.example.com where the fetch originated from. Not the host to which the request was being sent.
How do I get the request host and not the servers host?

Cypress sets "credentials": "omit" as opposed to "include" when Chrome fires api calls

This API call gets fired after clicking a login button. When doing it manually, the call looks like this:
fetch("https://someurl.io/account/login?ReturnUrl=somereturnurl", {
"headers": {
"accept": "application/json, text/plain, */*",
"accept-language": "en-US,en;q=0.9,es;q=0.8",
"content-type": "application/json;charset=UTF-8",
"requestverificationtoken": "some token",
"sec-ch-ua": "\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"98\", \"Google Chrome\";v=\"98\"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "\"macOS\"",
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin"
},
"referrer": "https://someurl.io/signin?ReturnUrl=somereturnurl",
"referrerPolicy": "strict-origin-when-cross-origin",
"body": "{\"username\":\"someuser\",\"password\":\"somepassword\",\"subscriberId\":\"someid\",\"isStaff\":somebool}",
"method": "POST",
"mode": "cors",
"credentials": "include"
});
This creates a .AspNetCore.Antiforgery cookie and then you login
When the test is ran via Cypress, the request is changed from "credentials": "include" to "credentials": "omit". No cookie is saved and the redirect fails due to
{type: "invalid-antiforgery-token", title: "Antiforgery token validation failed", detail: "",…}
code: 400
detail: ""
title: "Antiforgery token validation failed"
type: "invalid-antiforgery-token"
Has anyone ran into a similar issue and know how to make Cypress fire the same Request.credentials property?
Thank you so much in advance
That's it. I'm switching to Playwright.

Why does changing maxResults cause the total number of results to change in Google API / Gmail API?

Why does changing the maxResults parameter cause the resultSizeEstimate to drastically change when calling gmail.users.messages.list()?
The Google API docs lists resultSizeEstimate as: Estimated total number of results.
... which means this final result set should not change just by altering the number of items returned per page.
Example A: maxResults: 1 ... resultSizeEstimate: 8
{
"config": {
"url": "https://www.googleapis.com/gmail/v1/users/me/messages?q=before%3A2021%2F1%2F9&maxResults=1",
"method": "GET",
"headers": {
"Accept-Encoding": "gzip",
"User-Agent": "google-api-nodejs-client/0.7.2 (gzip)",
"Authorization": "Bearer [snip]",
"Accept": "application/json"
},
"params": {
"q": "before:2021/1/9",
"maxResults": 1
},
"responseType": "json"
},
"data": {
"messages": [ ... ],
"nextPageToken": "14911817971227869758",
"resultSizeEstimate": 8
},
"headers": {
"alt-svc": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-Q050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\"",
"cache-control": "private",
"connection": "close",
"content-encoding": "gzip",
"content-type": "application/json; charset=UTF-8",
"date": "Sun, 09 Jan 2022 12:59:48 GMT",
"server": "ESF",
"transfer-encoding": "chunked",
"vary": "Origin, X-Origin, Referer",
"x-content-type-options": "nosniff",
"x-frame-options": "SAMEORIGIN",
"x-xss-protection": "0"
},
"status": 200,
"statusText": "OK"
}
Example B: maxResults: 2 ... resultSizeEstimate: 12
{
"config": {
"url": "https://www.googleapis.com/gmail/v1/users/me/messages?q=before%3A2021%2F1%2F9&maxResults=2",
"method": "GET",
"headers": {
"Accept-Encoding": "gzip",
"User-Agent": "google-api-nodejs-client/0.7.2 (gzip)",
"Authorization": "Bearer [snip]",
"Accept": "application/json"
},
"params": {
"q": "before:2021/1/9",
"maxResults": 2
},
"responseType": "json"
},
"data": {
"messages": [ ... ],
"nextPageToken": "16903415066875011466",
"resultSizeEstimate": 12
},
"headers": {
"alt-svc": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-Q050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\"",
"cache-control": "private",
"connection": "close",
"content-encoding": "gzip",
"content-type": "application/json; charset=UTF-8",
"date": "Sun, 09 Jan 2022 13:10:48 GMT",
"server": "ESF",
"transfer-encoding": "chunked",
"vary": "Origin, X-Origin, Referer",
"x-content-type-options": "nosniff",
"x-frame-options": "SAMEORIGIN",
"x-xss-protection": "0"
},
"status": 200,
"statusText": "OK"
}
Example C: maxResults: (not set) ... resultSizeEstimate: 412
{
"config": {
"url": "https://www.googleapis.com/gmail/v1/users/me/messages?q=before%3A2021%2F1%2F9",
"method": "GET",
"headers": {
"Accept-Encoding": "gzip",
"User-Agent": "google-api-nodejs-client/0.7.2 (gzip)",
"Authorization": "Bearer [snip]",
"Accept": "application/json"
},
"params": {
"q": "before:2021/1/9"
},
"responseType": "json"
},
"data": {
"messages": [ ... ],
"nextPageToken": "16942818266524948378",
"resultSizeEstimate": 412
},
"headers": {
"alt-svc": "h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-Q050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\"",
"cache-control": "private",
"connection": "close",
"content-encoding": "gzip",
"content-type": "application/json; charset=UTF-8",
"date": "Sun, 09 Jan 2022 13:09:05 GMT",
"server": "ESF",
"transfer-encoding": "chunked",
"vary": "Origin, X-Origin, Referer",
"x-content-type-options": "nosniff",
"x-frame-options": "SAMEORIGIN",
"x-xss-protection": "0"
},
"status": 200,
"statusText": "OK"
}
This was previously reported in Issue Tracker and was considered to be intended behavior by Google, since resultSizeEstimate is not expected to be exact; it's an "estimate":
the reason why resultSizeEstimate shows differents values is due to its estimation. As mentioned in the documentation resultSizeEstimate is just an estimated total number of results but not the exact number of results.
Reference:
users.messages.list method returns different amount of messages when using “maxResults” parameter

Error message from API when sending POST with Cypress

I try to send an API request with cy.request but there seems to be something wrong with the data format. My code looks as follows:
cy.request({
url: Cypress.env("RtmApiUrl") + "/test-plan/",
method: "POST",
headers: {
"Authorization": "Bearer " + Cypress.env('RtmApiToken'),
"content-type": "application/json",
body: {
"projectKey": "QAIR",
"summary": "API Test Regression",
"description": "Full regression",
"parentTestKey": "F-QAIR-TP-8",
"priority": {
"id": 3,
"name": "Medium"
},
"status": {
"id": 10005,
"name": "Backlog"
},
"includedTestCases": []
},
},
});
And the console output from Cypress Test Runner:
CypressError: `cy.request()` failed on:
https://rtm-api.hexygen.com/api/test-plan/
The response we received from your web server was:
> 400: Bad Request
This was considered a failure because the status code was not `2xx` or `3xx`.
If you do not want status codes to cause failures pass the option: `failOnStatusCode: false`
-----------------------------------------------------------
The request we sent was:
Method: POST
URL: https://rtm-api.hexygen.com/api/test-plan/
Headers: {
"Connection": "keep-alive",
"Authorization": "Bearer <some Token>",
"content-type": "application/json",
"body": {
"projectKey": "QAIR",
"summary": "API Test Regression",
"description": "Full regression",
"parentTestKey": "F-QAIR-TP-8",
"priority": {
"id": 3,
"name": "Medium"
},
"status": {
"id": 10005,
"name": "Backlog"
},
"includedTestCases": []
},
"user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36",
"accept": "*/*",
"accept-encoding": "gzip, deflate",
"content-length": 0
}
-----------------------------------------------------------
The response we got was:
Status: 400 - Bad Request
Headers: {
"server": "Cowboy",
"connection": "keep-alive",
"x-content-type-options": "nosniff",
"x-xss-protection": "1; mode=block",
"cache-control": "no-cache, no-store, max-age=0, must-revalidate",
"pragma": "no-cache",
"expires": "0",
"strict-transport-security": "max-age=31536000 ; includeSubDomains",
"x-frame-options": "DENY",
"content-type": "application/json",
"content-length": "69",
"date": "Tue, 13 Jul 2021 07:32:36 GMT",
"via": "1.1 vegur"
}
Body: {
"errorMessages": [
"No content to map to Object due to end of input"
]
}
I already tried the same combination of header and body with Postman and curl and it worked. Is there something I missed?
Any help is appreciated. Thanks in advance.
Folks, I missed a bracket at the end of the headers block. So this was a real classic layer 8 issue...
cy.request({
url: Cypress.env("RtmApiUrl") + "/test-plan/",
method: "POST",
headers: {
"Authorization": "Bearer " + Cypress.env('RtmApiToken'),
"content-type": "application/json"
},
body: {
"projectKey": "QAIR",
"summary": "API Test Regression",
"description": "Full regression",
"parentTestKey": "F-QAIR-TP-8",
"priority": {
"id": 3,
"name": "Medium"
},
"status": {
"id": 10005,
"name": "Backlog"
},
"includedTestCases": []
},
},
});

ajax not working in firebase production environment but works on local host

ajax not working in firebase production environment but works on localhost ajax code
var settings = {
"async": true,
"crossDomain": true,
"url": "https://some_other_domain:3000/",
"method": "POST",
"dataType": "json",
"headers": {
"Access-Control-Allow-Origin" : "*",
"Access-Control-Allow-Headers" : "Origin, X-Requested-With, Content-Type, Accept",
"Access-Control-Allow-Methods" : "GET,PUT,POST,DELETE",
"Content-Type": "application/json",
"Cache-Control": "no-cache",
},
"processData": false,
"crossDomain":true,
"timeout": 3000,
"data": JSON.stringify(emailData)
}
$.ajax(settings)
.done(function (response) {
on firebase-hosting my request timeout(as seen on network tab in inspector, and console doesn't show any errors). on localhost it works fine. I tried on Mozila Firefox and Google Chrome.
You cannot call foreign domain using AJAX due to AJAX cross-domain policy.
Here is an alternative way to get data from a foreign domain.

Resources