Put call in reactjs - reactjs

This is my service method , where I need to do the put call to an API by passing an id. Is this the correct way, bcoz I am not able to hit my .put URL
ENDPOINTS = {
SAMPLE: "/sample",
};
This is my service method:
updateApi(): Promise<any> {
const config = {
headers: {
accept: "application/json",
"Content-Type": "application/json",
},
};
const data = {
// data
};
const id = sample.id;
return http
.put(`${this.ENDPOINTS.SAMPLE}${id}`, data, config)
.then((response) => {
return response.data;
})
.catch((error) => {
throw error;
});
}

I believe your issue is the line const {id} = sample.id;
This should instead be: const { id } = sample; or the equivalent const id = sample.id.
In addition, your API endpoint is missing a trailing /, so you should include it in your .put() call.
Example: ${this.ENDPOINTS.SAMPLE}/${id}

Not sure if you have any reason for using http here but if you are flexible then try fetch API available in react.
const requestOptions = {
method: 'PUT',
headers: {
accept: "application/json",
"Content-Type": "application/json",
},
body: data
};
fetch(`${ENDPOINTS.SAMPLE}/${sample.id}`, requestOptions)
.then(response => response.json())
.then(data => this.setState({ // update data here }));
If you are directly making call to API in your component then above code can be placed inside componentDidMount.
Let me know if you face any issue!

Related

update the state of my component with the response data after Post request with axios

I'm trying to update the state of my component with the response data after Post request with axios but it returns an empty array when I log out the updated state with console.log(), but shows the response.data information received with .then in axois in the broswer console. Please help me out
Code starts here
const [offers, setOffers] = useState({});//THIS IS THE STATE
const search async (e) => {
e.preventDefault();
const options = {
url: "localhost:8080/api/search",
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json;charset=UTF-8",
},
data,
};
axios(options)
.then((response) => {
console.log(response.data.data);// THIS RETURNS OBJECT DATA GOTTEN FROM THE SERVER AFTER POST REQUEST
setOffers(response.data.data); //IT DOES NOT UPDATE WITH RESPONSE DATA
console.log(offers); = IT RETURNS AND EMPTY ARRAY
})
.catch(function (error) {
if (error.response) {
setValerr(error.response.data.errors);
console.log(error.response);
}
});
};
thanks in advance
In react, setState is asynchronous, so when you call "setOffers" it is an asyncronous action.
Therefore when you call console.log, offers might not be updated yet.
You can read more about it here:
https://reactjs.org/docs/faq-state.html#when-is-setstate-asynchronous
To listen to the value of "offers" you might need to use useEffect
An example
const [offers, setOffers] = useState({}) //THIS IS THE STATE
const search = async (e) => {
e.preventDefault()
const options = {
url: 'localhost:8080/api/search',
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json;charset=UTF-8',
},
data,
}
axios(options)
.then((response) => {
console.log(response.data.data) // THIS RETURNS OBJECT DATA GOTTEN FROM THE SERVER AFTER POST REQUEST
setOffers(response.data.data) //IT DOES NOT UPDATE WITH RESPONSE DATA
console.log(offers)
})
.catch(function (error) {
if (error.response) {
setValerr(error.response.data.errors)
console.log(error.response)
}
})
}
useEffect(() => {
// This should log offers to the console if it has been set
if(offers) {
console.log(offers)
}
}, [offers])

React: Can't pass an id to an endpoint in order to display an image

I'm quite new to react and have an issue that i'm not sure whats wrong.
I have one external api with an endpoint that contains articles and another endpoint to get the images thats connected with the articles. I want to display the articles and the images together, but I can't get the images to show.
The flow is as follows:
First I find the article with the article api endpoint and the article id. And it looks like this:
const { itemId } = useParams()
const [article, setArticle] = useState([])
const [articleImg, setArticleImg] = useState('')
const [fileId, setFileId] = useState('')
useEffect(() => {
fetch(`https://api.fortnox.se/3/articles/${itemId}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
'Access-Token': accessToken,
'Client-Secret': clientSecret
}
})
.then((res) => res.json())
.then((data) => {
console.log(data)
setArticle(data.Article)
console.log(data)
})
}, [itemId])
In order to get the image to that article I have to find a FileId by searching the article number against ArticleFileConnections endpoint:
(Documentation)
useEffect(() => {
fetch(`https://api.fortnox.se/3/articlefileconnections/?articlenumber=${itemId}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
'Access-Token': accessToken,
'Client-Secret': clientSecret
}
})
.then((res) => res.json())
.then((data) => {
setFileId(data.ArticleFileConnections[0].FileId)
console.log(data.ArticleFileConnections[0].FileId) // Prints an id-number in the console
})
}, [])
When I have the FileId I use it with another endpoint called Archive in order to get the image. Documentation That fetch looks like this:
useEffect(() => {
fetch(`https://api.fortnox.se/3/archive/${fileId}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
'Access-Token': accessToken,
'Client-Secret': clientSecret
}
})
.then((res) => res.json())
.then((data) => {
setArticleImg(data)
console.log(data) // Prints an object thats a folder structure with an empty array
})
}, [])
I tried to change the ${fileid} to the actual id-number in the archive endpoint like this
https://api.fortnox.se/3/archive/8c05c536-c110-402d-82da-60f25f6b0e1c Then I get this error message in the console:
Uncaught (in promise) SyntaxError: Unexpected token � in JSON at position 0
But I don't get that error if I pass the ${fileid} in the endpoint https://api.fortnox.se/3/archive/${fileid} Although when I console.log the state fileId that I pass in it prints the fileId-number.
So what I expect is that the fileId-state that I use in the archive endpoint should display an image by writing this code.
<div>
<img src={articleImg} alt="product" />
</div>
I hope all this is understandable and I hope someone can help me with what i'm doing wrong.
Thank you.
Note: It all works in postman. When I try the endpoints like the flow above it shows the image with this endpoint https://api.fortnox.se/3/archive/8c05c536-c110-402d-82da-60f25f6b0e1c
Your useEffect for fetching the fileId is behaving as a componentDidMount. What you want instead is a componentDidUpdate behavior, which you can do by
useEffect(() => {
fetch(`https://api.fortnox.se/3/archive/${fileId}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
'Access-Token': accessToken,
'Client-Secret': clientSecret
}
})
.then((res) => res.json())
.then((data) => {
setArticleImg(data)
console.log(data) // Prints an object thats a folder structure with an empty array
})
}, [fileId]) // Notice the change here. It ensures that the useEffect is called every time the fileId is updated.

How to send body data and headers with axios get request?

I've tried
axios.get(url, {headers:{},data:{}})
But it doesn't work with this.
You should refer to https://github.com/axios/axios#request-config
Check the section for data and header.
As far as I know you can't send body data with GET request. With get you can have only Headers. Just simply change to POST and then you can do something like this :
const bodyParameters = {
key: "value",
};
const config = {
headers: { Authorization: `Bearer ${userToken}` },
};
axios.post("http://localhost:5000/user", bodyParameters, config)
.then((res)=> {
console.log(res)
})
.catch((err) => console.log(err));
};
or if you want to send headers with GET request
axios.get('/user', {
params: {
ID: 12345
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
})
.then(function () {
// always executed
});
// data is the data to be sent as the request body
// Only applicable for request methods 'PUT', 'POST', 'DELETE , and 'PATCH'
https://stackoverflow.com/a/54008789
yeah, it's true it doesn't work to send body in Axios get even if it works in the postman or the backend.
You can try this:
const getData = async () => {
try {
const response = await axios.post(`https://jsonplaceholder.typicode.com/posts`, {
method: 'POST',
body: JSON.stringify({
id: id,
title: 'title is here',
body: 'body is here',
userId: 1
}),
headers: {
"Content-type": "application/json; charset=UTF-8"
}
})
.then(response => response.json())
.then(json => console.log(json));
console.warn(response.data);
} catch (error) {
console.warn(error);
}
}
You can send data in a get request by using the config object and the params option of the config object. This is a workaround and it works, but on the server the data sent is available as request.query not as request.body. Based on the example below you would access your params data on your server using request.query.user_id. It should be noted that using this method will also append the params to your request url which could have unintended consequences based on your specific situation. For example, the url for the request below would be sent as example.com?user_id=1234. You can read more about the axios request config here.
axios.get(
'example.com/',
{
params: { user_id: 1234 },
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
},
);

axios.post returns bad request of 400 React Native

I'm getting my token from an API but unfortunately my API is returning 400 bad request. I've already checked my api via Postman and it's working fine there. Kindly let me know solution or any mistake.
async componentWillMount(){
axios.post('http://api.myapiurl.com/token', {
grant_type: 'PASSWORD',
username: 'MY_USERNAME',
password: 'MY_PASSWORD'
}, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
}
}).then(response => {
console.log(response.data)
}).catch(err => console.log("api Erorr: ", err.message))
}
error in response below
Request failed with status code 400
- node_modules\axios\lib\core\createError.js:16:24 in createError
- node_modules\axios\lib\core\settle.js:18:6 in settle
- ... 10 more stack frames from framework internals
It is Solved by using QueryString.stringify(). I just pass the body into QueryString.stringify() like below:
axios.post('http://api.apiurl.com/token', QueryString.stringify({
grant_type: 'MY_GRANT_TYPE',
username: 'MY_USERNAME',
password: 'MY_PASSWORD'
}), {
headers: {
"Content-Type": "application/x-www-form-urlencoded",
}
}).then(response => {
console.log(response.data)
}).catch(err => console.log("api Erorr: ", err.response))
From what I can see you are sending json data, but your Content-Type header is set to application/x-www-form-urlencoded; charset=UTF-8. if your api is expecting json then it should be application/json.
try using fetch instead, might be some axios bug, you dont need to add any libraries, here is an example:
fetch("http://api.myapiurl.com/token", {
method: "POST", // *GET, POST, PUT, DELETE, etc.
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
grant_type: "PASSWORD",
username: "MY_USERNAME",
password: "MY_PASSWORD"
})
})
.then(res => {
res.json();
})
.then(data => console.log(data)) // ur data is here
.catch(err => console.log("api Erorr: ", err));
First install the package axios from the url https://www.npmjs.com/package/react-native-axios
Then create two service for handling get and post request so that you can reuse them
GetService.js
import axios from 'axios';
let constant = {
baseurl:'https://www.sampleurl.com/'
};
let config = {
headers: {
'Content-Type': 'multipart/form-data',
'Accept': 'application/json'
}
};
export const GetService = (data,Path,jwtKey) => {
if(jwtKey != ''){
axios.defaults.headers.common['Authorization'] = 'Bearer '+jwtKey;
}
try{
return axios.get(
constant.baseUrl+'api/'+Path,
data,
config
);
}catch(error){
console.warn(error);
}
}
PostService.js
import axios from 'axios';
let constant = {
baseurl:'https://www.sampleurl.com/'
};
let config = {
headers: {
'Content-Type': 'multipart/form-data',
'Accept': 'application/json'
}
};
export const PostService = (data,Path,jwtKey) => {
if(jwtKey != ''){
axios.defaults.headers.common['Authorization'] = 'Bearer '+jwtKey;
}
try{
return axios.post(
constant.baseUrl+'api/'+Path,
data,
config
);
}catch(error){
console.warn(error);
}
}
Sample code for using get and post services is given below
import { PostService } from './PostService';
import { GetService } from './GetService';
let uploadData = new FormData();
uploadData.append('key1', this.state.value1);
uploadData.append('key2', this.state.value2);
//uploadData.append('uploads', { type: data.mime, uri: data.path, name: "samples" });
let jwtKey = ''; // Authentication key can be added here
PostService(uploadData, 'postUser.php', jwtKey).then((resp) => {
this.setState({ uploading: false });
// resp.data will contain json data from server
}).catch(err => {
// handle error here
});
GetService({}, 'getUser.php?uid='+uid, jwtKey).then((resp) => {
// resp.data will contain json data from server
}).catch(err => {
// handle error here
});
Reference from one of my another post Post action API with object parameter within the URL
If you have any doubts, feel free to know

axios post request to send form data

axios POST request is hitting the url on the controller but setting null values to my POJO class, when I go through developer tools in chrome, the payload contains data. What am I doing wrong?
Axios POST Request:
var body = {
userName: 'Fred',
userEmail: 'Flintstone#gmail.com'
}
axios({
method: 'post',
url: '/addUser',
data: body
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
Browser Response:
If I set headers as:
headers:{
Content-Type:'multipart/form-data'
}
The request throws the error
Error in posting multipart/form-data. Content-Type header is missing boundary
If I make the same request in postman it's working fine and sets values to my POJO class.
Can anyone explain how to set boundary or how can I send form data using axios.
You can post axios data by using FormData() like:
var bodyFormData = new FormData();
And then add the fields to the form you want to send:
bodyFormData.append('userName', 'Fred');
If you are uploading images, you may want to use .append
bodyFormData.append('image', imageFile);
And then you can use axios post method (You can amend it accordingly)
axios({
method: "post",
url: "myurl",
data: bodyFormData,
headers: { "Content-Type": "multipart/form-data" },
})
.then(function (response) {
//handle success
console.log(response);
})
.catch(function (response) {
//handle error
console.log(response);
});
Related GitHub issue:
Can't get a .post with 'Content-Type': 'multipart/form-data' to work # axios/axios
In my case I had to add the boundary to the header like the following:
const form = new FormData();
form.append(item.name, fs.createReadStream(pathToFile));
const response = await axios({
method: 'post',
url: 'http://www.yourserver.com/upload',
data: form,
headers: {
'Content-Type': `multipart/form-data; boundary=${form._boundary}`,
},
});
This solution is also useful if you're working with React Native.
Check out querystring.
You can use it as follows:
var querystring = require('querystring');
axios.post('http://something.com/', querystring.stringify({ foo: 'bar' }));
Upload (multiple) binary files
Node.js
Things become complicated when you want to post files via multipart/form-data, especially multiple binary files. Below is a working example:
const FormData = require('form-data')
const fs = require('fs')
const path = require('path')
const formData = new FormData()
formData.append('files[]', JSON.stringify({ to: [{ phoneNumber: process.env.RINGCENTRAL_RECEIVER }] }), 'test.json')
formData.append('files[]', fs.createReadStream(path.join(__dirname, 'test.png')), 'test.png')
await rc.post('/restapi/v1.0/account/~/extension/~/fax', formData, {
headers: formData.getHeaders()
})
Instead of headers: {'Content-Type': 'multipart/form-data' } I prefer headers: formData.getHeaders()
I use async and await above, you can change them to plain Promise statements if you don't like them
In order to add your own headers, you just headers: { ...yourHeaders, ...formData.getHeaders() }
Newly added content below:
Browser
Browser's FormData is different from the NPM package 'form-data'. The following code works for me in browser:
HTML:
<input type="file" id="image" accept="image/png"/>
JavaScript:
const formData = new FormData()
// add a non-binary file
formData.append('files[]', new Blob(['{"hello": "world"}'], { type: 'application/json' }), 'request.json')
// add a binary file
const element = document.getElementById('image')
const file = element.files[0]
formData.append('files[]', file, file.name)
await rc.post('/restapi/v1.0/account/~/extension/~/fax', formData)
2020 ES6 way of doing
Having the form in html I binded in data like so:
DATA:
form: {
name: 'Joan Cap de porc',
email: 'fake#email.com',
phone: 2323,
query: 'cap d\ou'
file: null,
legal: false
},
onSubmit:
async submitForm() {
const formData = new FormData()
Object.keys(this.form).forEach((key) => {
formData.append(key, this.form[key])
})
try {
await this.$axios.post('/ajax/contact/contact-us', formData)
this.$emit('formSent')
} catch (err) {
this.errors.push('form_error')
}
}
Using application/x-www-form-urlencoded format in axios
By default, axios serializes JavaScript objects to JSON. To send data
in the application/x-www-form-urlencoded format instead, you can use
one of the following options.
Browser
In a browser, you can use the URLSearchParams API as follows:
const params = new URLSearchParams();
params.append('param1', 'value1');
params.append('param2', 'value2');
axios.post('/foo', params);
Note that URLSearchParams is not supported by all browsers (see caniuse.com), but there is a polyfill available (make sure to polyfill the global environment).
Alternatively, you can encode data using the qs library:
const qs = require('qs');
axios.post('/foo', qs.stringify({ 'bar': 123 }));
Or in another way (ES6),
import qs from 'qs';
const data = { 'bar': 123 };
const options = {
method: 'POST',
headers: { 'content-type': 'application/x-www-form-urlencoded' },
data: qs.stringify(data),
url, };
axios(options);
Even More straightforward:
axios.post('/addUser',{
userName: 'Fred',
userEmail: 'Flintstone#gmail.com'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
import axios from "axios";
import qs from "qs";
const url = "https://yourapplicationbaseurl/api/user/authenticate";
let data = {
Email: "testuser#gmail.com",
Password: "Admin#123"
};
let options = {
method: "POST",
headers: { "content-type": "application/x-www-form-urlencoded" },
data: qs.stringify(data),
url
};
axios(options)
.then(res => {
console.log("yeh we have", res.data);
})
.catch(er => {
console.log("no data sorry ", er);
});
};
I had the similar issues when using FormData with axios to make calls on https://apps.dev.microsoft.com service and it error-red out with "The request body must contain the following parameter: 'grant_type'"
After reformatting the data from
{
grant_type: 'client_credentials',
id: '123',
secret: '456789'
}
to
"grant_type=client_credentials&id=123&secret=456789"
and the following code worked:
const config: AxiosRequestConfig = {
method: 'post',
url: https://apps.dev.microsoft.com/auth,
data: 'grant_type=client_credentials&id=123&secret=456789',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
}
};
axios(config)
.then(function (response) {
console.log(JSON.stringify(response.data));
})
.catch(function (error) {
console.log(error);
});
i needed to calculate the content length aswell
const formHeaders = form.getHeaders();
formHeaders["Content-Length"] = form.getLengthSync()
const config = {headers: formHeaders}
return axios.post(url, form, config)
.then(res => {
console.log(`form uploaded`)
})
A boundary (which is used, by the server, to parse the payload) is set when the request is sent. You can't obtain the boundary before making the request. So, a better way to get this is using getBoundary() from your FormData.
var formData = new FormData();
formData.append('userName', 'Fred');
formData.append('file0', fileZero);
formData.append('file1', fileOne);
axios({
method: "post",
url: "myurl",
data: formData,
headers: {
'Content-Type': `multipart/form-data; ${formData.getBoundary()}`,
})
.then(function (response) {
//handle success
console.log(response);
})
.catch(function (response) {
//handle error
console.log(response);
});
I needed to upload many files at once using axios and I struggled for a while because of the FormData API:
// const instance = axios.create(config);
let fd = new FormData();
for (const img of images) { // images is an array of File Object
fd.append('images', img, img.name); // multiple upload
}
const response = await instance({
method: 'post',
url: '/upload/',
data: fd
})
I did NOT specify the content-type: multipart/form-data header!
The above method worked for me but since it was something I needed often, I used a basic method for flat object. Note, I was also using Vue and not REACT
packageData: (data) => {
const form = new FormData()
for ( const key in data ) {
form.append(key, data[key]);
}
return form
}
Which worked for me until I ran into more complex data structures with nested objects and files which then let to the following
packageData: (obj, form, namespace) => {
for(const property in obj) {
// if form is passed in through recursion assign otherwise create new
const formData = form || new FormData()
let formKey
if(obj.hasOwnProperty(property)) {
if(namespace) {
formKey = namespace + '[' + property + ']';
} else {
formKey = property;
}
// if the property is an object, but not a File, use recursion.
if(typeof obj[property] === 'object' && !(obj[property] instanceof File)) {
packageData(obj[property], formData, property);
} else {
// if it's a string or a File
formData.append(formKey, obj[property]);
}
}
}
return formData;
}
For me it worked using axios, typescript and form-data(v4.0.0):
import FormData from "form-data";
import axios from "axios";
async function login() {
var data = new FormData();
data.append("User", "asdf");
const return = await axios.post(
"https://ptsv2.com/t/1q9gx-1652805776/post", data,
{ headers: data.getHeaders() }
);
console.log(return);
}
This should work well when needing to POST x-www-form-urlencoded data using axios from a NodeJS environment. You may need to add an Authorization header to the config.headers object if the endpoint requires authentication.
const config = {
headers: {
accept: 'application/json',
'cache-control': 'no-cache',
'content-type': 'application/x-www-form-urlencoded'
}
const params = new URLSearchParams({key1: value1, key2: value2});
return axios
.post(url, params.toString(), config)
.then((response) => {
return response.data;
})
.catch((error) => console.error(error));
In my case, the problem was that the format of the FormData append operation needed the additional "options" parameter filling in to define the filename thus:
var formData = new FormData();
formData.append(fieldName, fileBuffer, {filename: originalName});
I'm seeing a lot of complaints that axios is broken, but in fact the root cause is not using form-data properly. My versions are:
"axios": "^0.21.1",
"form-data": "^3.0.0",
On the receiving end I am processing this with multer, and the original problem was that the file array was not being filled - I was always getting back a request with no files parsed from the stream.
In addition, it was necessary to pass the form-data header set in the axios request:
const response = await axios.post(getBackendURL() + '/api/Documents/' + userId + '/createDocument', formData, {
headers: formData.getHeaders()
});
My entire function looks like this:
async function uploadDocumentTransaction(userId, fileBuffer, fieldName, originalName) {
var formData = new FormData();
formData.append(fieldName, fileBuffer, {filename: originalName});
try {
const response = await axios.post(
getBackendURL() + '/api/Documents/' + userId + '/createDocument',
formData,
{
headers: formData.getHeaders()
}
);
return response;
} catch (err) {
// error handling
}
}
The value of the "fieldName" is not significant, unless you have some receiving end processing that needs it.
https://www.npmjs.com/package/axios
Its Working
// "content-type": "application/x-www-form-urlencoded",
// commit this
import axios from 'axios';
let requestData = {
username : "abc#gmail.cm",
password: "123456"
};
const url = "Your Url Paste Here";
let options = {
method: "POST",
headers: {
'Content-type': 'application/json; charset=UTF-8',
Authorization: 'Bearer ' + "your token Paste Here",
},
data: JSON.stringify(requestData),
url
};
axios(options)
.then(response => {
console.log("K_____ res :- ", response);
console.log("K_____ res status:- ", response.status);
})
.catch(error => {
console.log("K_____ error :- ", error);
});
fetch request
fetch(url, {
method: 'POST',
body: JSON.stringify(requestPayload),
headers: {
'Content-type': 'application/json; charset=UTF-8',
Authorization: 'Bearer ' + token,
},
})
// .then((response) => response.json()) . // commit out this part if response body is empty
.then((json) => {
console.log("response :- ", json);
}).catch((error)=>{
console.log("Api call error ", error.message);
alert(error.message);
});
transformRequest: [
function(data, headers) {
headers["Content-Type"] = "application/json";
return JSON.stringify(data);
}
]
try this, it works

Resources