Attempting to log JSON response from REST API in JavaScript using Fetch - javascript

I have a small script that I have put together. The script does the following:
Defines several variables within an array
Passes those values to an API
API should return an access token
const fetch = require('node-fetch');
var orgInfo = {
client_id: 'idgoeshere',
client_secret: 'secretgoeshere',
username: 'usernamegoeshere',
password: 'passwordgoeshere',
grant_type: 'granttypegoeshere'
};
fetch('https://urlgoeshere', {
method: "GET",
body: JSON.stringify(orgInfo),
headers: {
"Content-Type": "application/json"
},
credentials: "include"
}).then(function(response) {
response.access_token
response.bearer
response.expires_in
response.scope
return repsonse.text()
}, function(error) {
error.message
})
console.log(orgInfo);
console.log(response.access_token);
When I log orgInfo, I do get the following output:
{ client_id: 'idgoeshere',
client_secret: 'secretgoeshere',
username: 'usernamegoeshere',
password: 'passwordgoeshere',
grant_type: 'granttypegoeshere' }
When I try to log response.access_token, I get a ReferenceError: response is not defined
My questions are:
Does response need to be defined? Obviously, Im being yelled at because it isnt.
Is there a way to see if I am getting anything back from the API automagically?
Im not looking for someone to spoon-feed me an answer, rather I am simply looking for a push in the right direction. That would be stellar.
Thanks
UPDATE
So this is what I have:
const fetch = require('node-fetch');
const orgInfo = {
client_id: ' ',
client_secret: ' ',
username: ' ',
password: ' ',
grant_type: ' '
};
(async() => {
const response = await fetch('https:// ', {
method: "GET",
body: JSON.stringify(orgInfo),
headers: {
"Content-Type": "application/json"
}
});
const data = await response.json();
console.log(data)
})
This returns no errors when running but also doesnt return the value of data

return repsonse.text() should be ----> return response.text()
According to Fetch Documentation
"The Response interface of the Fetch API represents the response to a
request. You can create a new Response object using the Response.Response() constructor, but you are more likely to encounter a Response object being returned as the result of another API operation—for example, a service worker Fetchevent.respondWith, or a simple fetch().
For your question "Is there a way to see if I am getting anything back from the API automagically?"
You can try using console.log(response.status); which will give you the status code of your request. These codes can be found HERE. And an example of this being used HERE.
I highly recommend trying to use Postman or Thunder-client if you can which simplifies all of this and gives you everything you need to know about the response. It is very useful to test API calls and know exactly what is happening. You also have the ability to see your call written in other languages automatically.

fetch returns a Promise object.
A Promise represents the eventual completion (or failure) of an asynchronous operation and its resulting value. That means response.access_token is only guaranteed to have a value (if any) inside the .then block as response is only evaluated when the promise has been fulfilled.
The reason you get nothing in the console is that you are trying to access access_token when it is not guaranteed to have a value (and thus console.log outputs nothing - there is nothing to output).
To fix this, you need to access the access_token property when you are guaranteed to have a response.
That is after the promise has been fulfilled, so either:
Move the console.log(response.access_token); inside the .then clause
Or a cleaner, more modern solution would be to:
Use await (equivalent syntactical sugar)
N.B. The Response object is the representation of the entire HTTP response.
You're using response.text() which will parse the response body as a string, not a JS object with properties.
I'm assuming you want to parse the body content from the Response object as JSON into a JS object. In that case, use the json() method which will then return a 2nd promise resolving with the JavaScript object obtained from the parsing of the response body.
The result should have the access_token property you want (considering the API endpoint returns it).
This should work:
const response = await fetch('https://urlgoeshere', {
method: "GET",
body: JSON.stringify(orgInfo),
headers: {
"Content-Type": "application/json"
};
const data = await response.json();
console.log(data.access_token);
console.log(data.bearer);
console.log(data.expires_in);
console.log(data.scope);
...

const fetch = require('node-fetch');
var orgInfo = {
client_id: 'idgoeshere',
client_secret: 'secretgoeshere',
username: 'usernamegoeshere',
password: 'passwordgoeshere',
grant_type: 'granttypegoeshere'
};
fetch('https://urlgoeshere', {
method: "GET",
body: JSON.stringify(orgInfo),
headers: {
"Content-Type": "application/json"
},
credentials: "include"
}).then(function(response) {
response.access_token
response.bearer
response.expires_in
response.scope
console.log(response.access_token);
return repsonse.text()
}, function(error) {
error.message
})
console.log(orgInfo);
response ins scoped inside the function called by the then method so it is accessible only inside of this function

Related

How to pass null value in fetch POST request

I'd like to pass a null value in a fetch POST request.
To illustrate this example, here is a screenshot from my API client, Insomnia (equivalent to Postman).
This POST in insomnia returns the desired results.
Now I try to do it in javascript using the following code:
let decal_colo = document.querySelector('#decal_colo').value.trim();
if (!decal_colo) {decal_colo=null};
let owner = document.querySelector('#owner').value.trim();
console.log(decal_colo, owner)
const response = await fetch('/api/testFilter', {
method: 'POST',
body: JSON.stringify({ decal_colo, owner }),
headers: { 'Content-Type': 'application/json' },
});
if (response.ok) {
const filteredData = await response.json();
console.log(filteredData);
You can see I am attempting to pass the null value in this line if the user does not give any input:
if (!decal_colo) {decal_colo=null};
This will console.log a value of null but my API route is not interpreting this in the same way. There is no error, but zero results are returned. I have looked at the database and there should be some results returned.
If it is helpful, I am using sequelize to create my Model and Controllers
How can I pass null in the correct way?
In the Insomnia app you are sending a JSON object but in the JavaScript code you are sending a string. Replace the body: JSON.Stringify with this:
body: { decal_colo, owner }

graphql query with fetch producing 400 bad request

I am trying to write a basic graphql query with fetch that works when using apollo client. But it does not work with node-fetch.
The type definitions look like this:
type Query {
findLeadStat(print: PrintInput!): LeadStatWithPrint
}
input PrintInput {
printa: String!
service: String
}
type LeadStatWithPrint {
answered: Int!
printa: String!
service: String
}
This is the node-fetch query:
const fetch = require('node-fetch');
( async () => {
const uri = `http://localhost:3000/graphql/v1`;
const query = `
query findLeadStat(print: PrintInput!) {
findLeadStat(print: $print){
answered
printa
service
}
}
`;
// I also tried add a query: key inside data object
const data = {
print: {
printa: "62f69234a7901e3659bf67ea2f1a758d",
service: "abc"
}
}
const response = await fetch(uri, {
method: 'post',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({query, data})
});
console.log('and the resp: ', response);
})()
It gives me:
url: 'http://localhost:3000/graphql/v1',
status: 400,
statusText: 'Bad Request',
It works in Apollo GraphQL Client. Why doesn't it work with fetch?
So when I was using async await with node-fetch, the response was pretty much useless. It was just telling me there was a 400 bad request error and then give me this long object of properties, none of them containing the actual error message.
But when I changed the fetch call to this:
const response = await fetch(uri, {
method: 'post',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ query, variables}) // same as query: query, variables: variables
})
.then(res => res.json())
.then(json => console.log(json))
.catch(err => console.error('ERROR: ', err));
There two lines right here:
.then(res => res.json())
.then(json => console.log(json))
made it clear what the issue was:
{
errors: [
{
message: 'Syntax Error: Expected $, found Name "fingeprint"',
locations: [Array],
extensions: [Object]
}
]
}
It appears node-fetch has two async events occurring and so await had to be used twice:
const response = await fetch(uri, {
method: 'post',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ query, variables}) // same as query: query, variables: variables
})
console.log('and the resp: ', await response.json());
A 400 status indicates your query was invalid or malformed. When this happens, the response will include a JSON body with an errors array that can be inspected to determine what exactly went wrong.
In this particular case, the issue is that your query includes a non-nullable variable ($print) but this variable was not provided along with the query.
When making a GraphQL request, the request body should be a JSON object with a query property and two other optional properties -- variables and operationName. operationName is used to identify which operation to execute if multiple operations were included in the provided document (the query property). Any non-nullable variables defined in the executed operation must be included as properties under the variables property, which is also an object. Nullable properties may be omitted altogether.
In other words, you need to change the data property in your request to variables in order for the server to recognize that the variable was provided with the request.

How to return a response from a fetch in javascript

I am having trouble returning the response for a API call in my React Native project.
let response = fetch('http://3.133.123.120:8000/auth/token', {
method: "POST",
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
client_id: 'NTMtzF7gzZPU9Ka35UFsDHvpR8e4D1Fy4OPRsurx',
grant_type: 'password',
username: user,
password: pass,
})
})
.then((response) => response.json())
.then((response) => this.setState({jsonData: response}))
.then(() => alert('resposne jsonData: ' + JSON.stringify(this.state)));
alert('resposne jsonData: ' + JSON.stringify(response))
The code above returns the correct response in the bottom .then() statement, however, I have not been able to use the data outside of the fetch() statement.
Anything I've tried to use outside of the fetch() (like my alert in bottom line) has given me the following...
{"_40":0,"_65":0,_55":null,"_72":null}
Please also note this is all inside a React class Component
fetch returns a Promise: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
You already have access to the value in that final then. If you're looking for a way to use the value below without using a callback, you could consider async/await style and wrapping this code in a function like so:
const fetchData = async () => {
const results = await fetch() // put your fetch here
alert(results.json());
};
fetch info:
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
async/await info:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await

Dynamically decide which Fetch response method to use

I work with a Backend API which returns different data types for different requests to the same endpoint. While a more appropriate solution would be to unify the data type returned, legacy, time and lack of tests play against this solution.
I am centralizing my call method to be used by other parts of the application which need to call the endpoint. This call method implements fetch. For information:
export default function call<P> (method: TCallMethod, payload: P, parameter?: string): Promise<IServerResponseObject> {
const url: string = buildUrl(parameter);
const body: string | null = payload ? JSON.stringify(payload) : null;
return fetch(url, {
method,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${getAuthToken()}`
},
body
}).then(async (response) => {
let body: IServerResponseObjectBody = {
message: '',
code: ''
};
if (response) {
body = await response.json();
}
return {
status: response.status,
body
};
});
}
As I receive data, I am using the Response.json method to decode it.
if (response) {
body = await response.json();
}
The problem is that sometimes I receive no data (when the user is not authenticated - although that's an edge case) or the server responds with just a boolean.
In that case, the json() execution fails, because we are not handling JSON data.
ie:
FetchError: invalid json response body at http://localhost:4545/api/definition/isNameUnique/used%20name reason: Unexpected end of JSON input
I am wondering if there is a cleaner way than nesting try/catches to determine which decode method to use from the ones available: https://developer.mozilla.org/en-US/docs/Web/API/Body#Methods
This feels like a potential solution: https://developer.mozilla.org/en-US/docs/Web/API/Body#Properties but the documentation is not too explicit and lacks examples on how to use it.
It sounds to me like you want to use text to read the response, then look at the resulting text and decide what to do. Roughly:
const text = await response.text();
if (!text) {
// no response, act accordingly
} else if (reBool.test(text)) {
// boolean response, determine whether it's true or false and act on it
} else {
// JSON response, parse it
data = JSON.parse(text);
// ...then use it
}
...where reBool is a regular expression to test for the boolean the server sometimes returns, for instance /^(?:true|false)$/i.
If the response may have whitespace, you might trim the result of response.text().
There are some unrelated things you might also want to do:
You're not checking for a successful response (this is a mistake a lot of people make, so many I wrote it up on my otherwise-anemic little blog). Check response.ok before using json or text, etc.
It doesn't make much sense to pass an async function into then as a callback. If you're going to go async, do it earlier, by making call an async function, then work with await throughout the body rather than mixing your metaphors...
Addressing those and folding in the main answer above (you'll need to adjust as necessary, either IServerResponseObject needs changing or you need to do something different with boolean responses):
const reBool = /^(?:true|false)$/i;
export default async function call<P> (method: TCallMethod, payload: P, parameter?: string): Promise<IServerResponseObject> {
const url: string = buildUrl(parameter);
const body: string | null = payload ? JSON.stringify(payload) : null;
const response = await fetch(url, {
method,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: `Bearer ${getAuthToken()}`
},
body
});
const {status} = response;
if (!response.ok) {
throw new Error("HTTP error " + status); // Or `return {status};` or similar, but making it an error is useful
}
const text = (await response.text()).trim();
let result = {status};
if (!text) {
// blank, act accordingly, perhaps:
result.body = null;
} else if (reBool.test(text)) {
result.body = text === "true";
} else {
result.body = JSON.parse(text);
}
return result;
}

Javascript await fetch GET request with number of params

React JSX project.
I'm trying to execute await fetch GET request with number of params, fails with Uncaught SyntaxError: Unexpected identifier error.
While executing the same request with Postman, it works fine.
Some syntax issue I have. What am I doing wrong?
First of all, I'm initializing the uri to some proper value.
Secondly, I'm preparing the GET options:
var options = (payload) => {
return {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
param: JSON.stringify(payload) //payload is {domainName: "idoidoido.info"}
};
};
Then, await fetch:
const response = await fetch(uri, options(param));
And, it fails with Uncaught SyntaxError: Unexpected identifier error...
I'm assuming the second parameter of fetch takes an object, but your options is a function, which must be called with the payload, so I should think your code should be
const response = await fetch(uri, options(somePayload));
Well, first of all, I hope you're using a transpiler like BabelJS, otherwise this would would fail on like 99% of all targets at present.
Your code looks fine. Since fetch returns a Promise, await can deal with it. But you have to make sure that your await statement always is located within an async function declaration. Otherwise an error is thrown at you.
So make sure your calling line has a structure like
async function getData( uri, options ) {
const response = await fetch(uri, options);
}
Succeded to solve this. Looks like query params can't be part of fetch GET request.
Solved this by preparing the request URL beforehand with URI.js.
So, the option:
const options = () => {
return {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
credentials: 'same-origin'
};
};
Then, await fetch:
const URI = require('urijs');
const request = new URI(uri).addSearch(params).toString();
const response = await fetch(uri, options());
The addSearch(params) appending the params nicely to the url:
URI("?hello=world")
.addSearch("hello", "mars")
// -> ?hello=world&hello=mars
.addSearch({ foo: ["bar", "baz"] })
// -> ?hello=world&hello=mars&foo=bar&foo=baz

Categories