I am writing an app in React-Native that makes a request to the Hubspot API. This has given me issues, as I initially attempted to make the request using the Node JS request module, which does not work with React Native when using Expo. I am now attempting to make the request to the Hubspot API with React Native's own Fetch API, but am having trouble translating my initial code written using the Node JS request module. I get an error when making a request to the Hubspot API. I've attached the two versions of the code to this question. Could anyone explain what is wrong with my translation of the Node JS code? Any advice would be much appreciated. Node JS version (request succeeds)
Fetch version (request fails)
Welcome to Stack Overflow :)
I think your fetch request is not written correctly. Instead of creating a new Request const you could pass all your params to the fetch function directly:
fetch('https://hubapi.com/whatever/CONFIDENTIAL', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
properties
})
})
.catch((error) => {
console.error(error);
});
Notice I also added a catch block at the end of the request. If it still fails you should at least get a better understanding of what exactly is failing.
The code I quoted above is taken from the React Native docs, link here. The docs contain a lot of great examples, including using a async/await and other networking libraries.
I tested it for you in my react native project. The request succeeds, of course I get This hapikey (CONFIDENTIAL) doesn't exist as response, because I don't have a key, but the query runs successfully:
try {
const response = await fetch(
'https://api.hubapi.com/contacts/v1/contact/?hapikey=CONFIDENTIAL',
{
method: 'POST',
headers: new Headers({ 'Content-Type': 'application/json' }),
body: JSON.stringify({
"properties": [
{ property: 'email', value: 'test#email.com' },
{ property: 'firstname', value: 'Sean' },
{ property: 'lastname', value: 'Smith' },
]
})
}
);
const responseJson = await response.json();
console.log("response from hubapi:", responseJson)
} catch (e) {
console.error("Error on fetch request:", e);
}
Related
I have a React application where I am changing POST method to GET with the request body as it is. It works fine with POST request however when I change the method to GET, it gives me error-
message: "org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing: public
My Front End Code-
export const setData = (getData) => dispatch => {
axios({
method: 'GET',
url: 'http://localhost:8080/api',
headers: {
'Content-Type': 'application/json'
},
data: getData
})
.then (response => {
dispatch({
type: API_DATA,
payload: response.data
})
dispatch({
type: SET_SEARCH_LOADER,
payload: false
})
})
.catch(function(error) {
})
}
Can someone let me know what I am missing here. As per my understanding, http allows to have a request body for GET method.
As per my understanding, http allows to have a request body for GET method.
While this is technically true (although it may be more accurate to say that it just doesn't explicitly disallow it), it's a very odd thing to do, and most systems do not expect GET requests to have bodies.
Consequently, plenty of libraries will not handle this.
The documentation for Axois says:
// `data` is the data to be sent as the request body
// Only applicable for request methods 'PUT', 'POST', and 'PATCH'
Under the hood, if you run Axios client side in a web browser, it will use XMLHttpRequest. If you look at the specification for that it says:
client . send([body = null])
Initiates the request. The body argument provides the request body, if any, and is ignored if the request method is GET or HEAD.
If you want to send parameters with get request in axios, you should send parameters as params.
If you want to set "Content-type":"application/json" and send params with get request, you should also send an empty data object.
For example:
const AUTH_TOKEN = 'Bearer token'
const config = {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': AUTH_TOKEN,
},
data: {},
params: {
"post_id": 1
}
}
axios.get("http://localhost/api/v1/posts/", config)
This is not axios, the error origniates from the java backend you're talking to. The public field in your request body is missing.
If you just want to send the data as parameters (which would be odd), pass it using params instead of data (as shown here: https://github.com/axios/axios#example).
I personally don't think your API should support GET with a request body (talk to the devs and ask for documentation).
There were similar discussion here Firebase API doesn't respond with common error codes using Axios on react native, but guy was using Axios. I would like to use Fetch API, and hope there are similar solution using this API for current case.
The issue is when I get error from Firebase REST API statusText of response is empty. I only got status code.
If I will make same request with the same url and options using Axios I will get error description which defied by Firebase API (like TOKEN_EXPIRED, USER_DISABLED, USER_NOT_FOUND, INVALID_REFRESH_TOKEN, MISSING_REFRESH_TOKEN etc.) using console.log(error.response.data.error.message)
How I can achieve same output with Fetch API?
const response = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: bodyString
});
if (response.ok) {
const payload = await response.json();
return payload as HttpResponse;
} else {
throw new Error(`Server error: ${response.statusText}. Status: ${response.status}`);
}
I don't know how I missed to check this.
The solution: await response.text()
I have a React application where I am changing POST method to GET with the request body as it is. It works fine with POST request however when I change the method to GET, it gives me error-
message: "org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing: public
My Front End Code-
export const setData = (getData) => dispatch => {
axios({
method: 'GET',
url: 'http://localhost:8080/api',
headers: {
'Content-Type': 'application/json'
},
data: getData
})
.then (response => {
dispatch({
type: API_DATA,
payload: response.data
})
dispatch({
type: SET_SEARCH_LOADER,
payload: false
})
})
.catch(function(error) {
})
}
Can someone let me know what I am missing here. As per my understanding, http allows to have a request body for GET method.
As per my understanding, http allows to have a request body for GET method.
While this is technically true (although it may be more accurate to say that it just doesn't explicitly disallow it), it's a very odd thing to do, and most systems do not expect GET requests to have bodies.
Consequently, plenty of libraries will not handle this.
The documentation for Axois says:
// `data` is the data to be sent as the request body
// Only applicable for request methods 'PUT', 'POST', and 'PATCH'
Under the hood, if you run Axios client side in a web browser, it will use XMLHttpRequest. If you look at the specification for that it says:
client . send([body = null])
Initiates the request. The body argument provides the request body, if any, and is ignored if the request method is GET or HEAD.
If you want to send parameters with get request in axios, you should send parameters as params.
If you want to set "Content-type":"application/json" and send params with get request, you should also send an empty data object.
For example:
const AUTH_TOKEN = 'Bearer token'
const config = {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': AUTH_TOKEN,
},
data: {},
params: {
"post_id": 1
}
}
axios.get("http://localhost/api/v1/posts/", config)
This is not axios, the error origniates from the java backend you're talking to. The public field in your request body is missing.
If you just want to send the data as parameters (which would be odd), pass it using params instead of data (as shown here: https://github.com/axios/axios#example).
I personally don't think your API should support GET with a request body (talk to the devs and ask for documentation).
can somebody explain to me why when I am using fetch and accessed my nodejs api - it is authorized but when I tried using axios to access my api - it is unauthorized.
This is the code I am using in fetch (It came from tutorial: https://medium.com/#alexanderleon/implement-social-authentication-with-react-restful-api-9b44f4714fa) Bec I am studying his way of authenticating using passport-facebook-token.
(client -->(login fbsdk)--> fb --> (access token)--> client -->(pass access token)--> nodejs api --> (get credentials) --> passport-fb-token --> (send credentials) --> nodejs api --> (credentials)--> client)
const tokenBlob = new Blob([JSON.stringify({access_token: response.accessToken}, null, 2)], {type : 'application/json'});
const options = {
method: 'POST',
body: tokenBlob,
mode: 'cors',
cache: 'default'
};
fetch('http://localhost:4000/api/v1/auth/facebook', options).then(r => {
const token = r.headers.get('x-auth-token');
r.json().then(user => {
if (token) {
this.setState({isAuthenticated: true, user, token})
}
});
})
This is the code of my axios
axios({
method: 'post',
url: 'http://localhost:4000/api/v1/auth/facebook',
headers: {
'Access-Control-Allow-Origin': '*',
},
data: {
access_token: response.access_token
}
})
.then((res) => console.log(res))
.catch((err) => console.log(err));
You should configure axios to use your token in one central place. For example
export const configureAxios = (token) => {
axios.interceptors.request.use(req => {
// don't give our token to non-our servers
if (isDomesticRequest(req.url)) {
req.headers.Authorization = `Bearer ${token}`;
}
return req;
});
}
This blog should help you get your answer in detail:
Fetch vs. Axios.js for making http requests
Axios is a Javascript library used to make http requests from node.js
or XMLHttpRequests from the browser and it supports the Promise API
that is native to JS ES6. Another feature that it has over .fetch() is
that it performs automatic transforms of JSON data.
If you use .fetch() there is a two-step process when handing JSON
data. The first is to make the actual request and then the second is
to call the .json() method on the response.
The .fetch() method is a great step in the right direction of getting
http requests native in ES6, but just know that if you use it there
are a couple of gotchas that might be better handled by third-party
libraries like Axios.
I'm trying to get an OAuth token for the Reddit API following the Application Only OAuth instructions. My reddit app is an installed app, so for my grant_type I'm using https://oauth.reddit.com/grants/installed_client.
Currently I'm running a very short JS script to query the API and get a token:
const APP_ID = 'MY_APP_ID'
const DEVICE_ID = 'TRACKING_ID_20_TO_30_CHARS'
let form = new FormData()
form.append('grant_type', 'https://oauth.reddit.com/grants/installed_client')
form.append('device_id', DEVICE_ID)
fetch('https://www.reddit.com/api/v1/access_token', {
method: 'POST',
headers: new Headers({
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': `Basic ${btoa(`${APP_ID}:`)}`,
}),
body: form })
.then(handleResponse)
.then(function(data) {
console.log(data)
})
.catch(error => console.error(error))
function handleResponse(response) {
return response.json()
}
(Note: running the snippet as-is will give you a NetworkError because the APP_ID isn't a real one and I don't want to give mine out.)
The response I get is:
{
"error": "unsupported_grant_type"
}
When I try the same API request using a REST client I get back the expected response, so this makes me think that the problem is JavaScript-related. Since the grant_type matches what the instructions say I'm not really sure what to do with the error. I'm hoping someone else more experienced with OAuth will know what is going on here.
The problem was the use of the FormData object. In earlier stages of troubleshooting I found this answer on Reddit and decided to use it, but that didn't work for me.
It was submitting the data as multipart/form-data rather than application/x-www-form-urlencoded, which Reddit's OAuth server did not like. I wrote a helper function based on this answer which did the trick:
function urlEncode(data) {
let out = [];
for (let key in data) {
out.push(`${key}=${encodeURIComponent(data[key])}`);
}
return out.join('&')
}