Sending data as key-value pair using fetch polyfill in react-native - http

The following code is to make HTTP POST request with fetch polyfill:
fetch(url, {
method: 'post',
body: JSON.stringify({
token: this.state.token,
}),
})
.then((response) => response.json())
.then((responseData) => {
console.log(responseData);
})
.done();
This request sends data as a stringified JSON obj. Is there a way to send data as key-value pair similar to requests? post(URL, data=payload) in python.

Sounds like you want the same format as a querystring, so import/require a package like https://www.npmjs.com/package/query-string which doesn't appear to depend on any browser features and has a stringify method:
queryString.stringify({
foo: 'bar',
nested: JSON.stringify({
unicorn: 'cake',
}),
});
//=> foo=bar&nested=%7B%22unicorn%22%3A%22cake%22%7D
Alternatively you could just use the relevant part of its source code, though this would still be subject to its license:
function toQueryString(obj) {
return obj
? Object.keys(obj)
.sort()
.map(function (key) {
var val = obj[key];
if (Array.isArray(val)) {
return val
.sort()
.map(function (val2) {
return encodeURIComponent(key) + '=' + encodeURIComponent(val2);
})
.join('&');
}
return encodeURIComponent(key) + '=' + encodeURIComponent(val);
})
.join('&')
: '';
}
You can then use the return value in your body parameter in fetch:
fetch(url, {
method: 'post',
body: toQueryString({ token: this.state.token }),
});

Sure. Look at the fetch documentation in github: https://github.com/github/fetch
It uses document/DOM web, but it should be the same for react-native case - just use FormData object and append all the form fields to send.
var form = document.querySelector('form')
fetch('/users', {
method: 'post',
body: new FormData(form)
})
And:
var input = document.querySelector('input[type="file"]')
var data = new FormData()
data.append('file', input.files[0])
data.append('user', 'hubot')
fetch('/avatars', {
method: 'post',
body: data
})

Related

Why is PUT throwing an Error 400 in my WebAPI?

First time working with web APIs and I can't seem to make the PUT method work, while everything works fine (get, post and delete).
I'm trying to do, what I think it is, a very simple call to update testimonials. These will have an image file, name and text. The problem is I'm getting error 400 when trying to update them using a PUT call.
I'm using FormData to send the data since I need to also send the image file and the rest of the form (the URI is "/api/testimonials", and the Id is a guid):
function updateItem() {
const itemId = document.getElementById('edit-id').value;
const item = {
id: itemId,
name: document.getElementById('edit-name').value.trim(),
text: document.getElementById('edit-text').value.trim(),
};
const formData = new FormData();
formData.append('file', document.getElementById('edit-file').files[0]);
formData.append('jsonString', JSON.stringify(item));
fetch(`${uri}/${itemId}`, {
method: 'PUT',
contentType: 'false',
processData: 'false',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: formData
})
.then(() => getItems())
.catch(error => console.error('Unable to update item.', error));
closeInput();
return false;
}
and this is the method in the TestimonialsController:
[HttpPut("{id}")]
public async Task<IActionResult> PutTestimonial(string id, [FromForm] IFormFile? file, [FromForm] string jsonString)
{
...
}
Other methods like POST and Delete, that also pass an Id or data work just fine, but PUT is not being called.
POST method
[HttpPost]
public async Task<ActionResult<TestimonialDTO>> PostDepoimento([FromForm] IFormFile? arquivo, [FromForm] string jsonString)
{
...
}
function addItem() {
const addNameTextbox = document.getElementById('add-name');
const addTextTextbox = document.getElementById('add-text');
const item = {
name: addNameTextbox.value.trim(),
text: addTextTextbox.value.trim(),
};
const formData = new FormData();
formData.append('file', document.getElementById('add-file').files[0]);
formData.append('jsonString', JSON.stringify(item));
fetch(uri, {
method: 'POST',
contentType: 'false',
processData: 'false',
body: formData
})
.then(response => response.json())
.then(() => {
getItems();
addNameTextbox.value = '';
addTextTextbox.value = '';
})
.catch(error => console.error('Unable to add item.', error));
}
DELETE method
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTestimonial(string id)
{
...
}
function deleteItem(id) {
fetch(`${uri}/${id}`, {
method: 'DELETE'
})
.then(() => getItems())
.catch(error => console.error('Unable to delete item.', error));
}
Could you help me identify why is the PUT method not being called? Is there anything wrong in the way I'm calling the method/passing data?
400 error is because [FromForm] does not allow application/json Content-Type. Just remove the header in your updateItem function:
headers: {
'Accept': 'application/json',
//'Content-Type': 'application/json'
},
FromForm occurs at the parameter binding stage, which is part of the request pipeline that necessarily occurs before entry into the endpoint. This is why under debug, for example, your breakpoints wouldn't hit.

javascript post fetch request gone wrong

please, help me check this post request.
I've been looking at it since yesterday, I don't know what is wrong with it
maybe I need another developer's pairs of eyes.
thanks in advance
buttons.addEventListener('click', ()=>{
fetch("https://jsonplaceholder.typicode.com/comments", config)
.then(res=>{
res.json();
}).then(datae=>{
console.log(datae);
})
});
const config = {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(newName)
}
buttons.addEventListener('click', () => {
fetch('https://jsonplaceholder.typicode.com/comments', config)
.then((res) => {
return res.json()
})
.then((datae) => {
console.log(datae)
})
})
you just need to return res.json()
this should work, but remember that the function you pass to the .then function has access to the returned value from the previous .then.
fetch returns a promise that resolves into an object with the .json function
so in the first .then it will get that object and you need to return res.json() which returns a promise that will be resolved to the JSON data
so in the next .then you can use that data
I hope I was clear
note:
.then function returns a promise ( always )
also maybe you have an error in the config variable, what you pass to the JSON.stringify function should be a valid javascript object
const config = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'rowadz' }),
}

I tried to make a POST with react, it works, but my objects are empty when I verify in Postman

I have this POST to send the score and the name of a player after finnishing the game
var sendScoreToAPI = (val) => {
//get player name from browser prompt
var playerName = prompt("Good Game, Well Played! Please enter your name: ", "Victor");
if (playerName != null) {
var dataToSave = {
//replace 10 with your actual variable (probably this.state.gameScore or this.state.time)
playerName: playerName,
playerScore: val,
//currentTime: new Date()
};
console.log(dataToSave)
// Actual API call
fetch(
"https://localhost:44327/api/MineSweeper", // replace with the url to your API
{method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(dataToSave)}
)
.then(res => res.json())
.then(
(result) => {
alert('GG '+playerName + "! Ai un scor de "+val);
},
// Note: it's important to handle errors here
(error) => {
alert('Bad API call');
console.log(error);
}
)
}
}
It works, in the console I see the right atributtes, but after the POST is empty when I try to GET from Postman.

Fetch: Can you pass parameters to the server

I'm using a basic fetch to obtain data from an express server that queries the data from a database. So I want to do a login system, i want to send the user/password from the input fields with the fetch request. so i can perform the logical check to see if password matches the data in the server. and respond with the result.
Is it possible to do a fetch that can pass parameters?
Updated Code Below:
let fetchData = {
method: "post",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
username: this.state.user,
password: this.state.password
})
}
var fromServer = fetch('http://localhost:3000/', fetchData)
.then(function(response){
if( !response.ok){
throw Error (response.statusText);
}
return response.json();
})
.then(function(response) {
console.log(response);
})
.catch(error => console.log("there was an error --> " + error));
Express function
app.post('/', function(req, res){
var uname = req.body.username;
var pw = req.body.password;
console.log(uname);
console.log(pw);
});
Of course you can!
Here is an example of Fetch using a POST request:
fetch("http://example.com/api/endpoint/", {
method: "post",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
//make sure to serialize your JSON body
body: JSON.stringify({
name: myName,
password: myPassword
})
})
.then( (response) => {
//do something awesome that makes the world a better place
});
I've answered this question before, check this for more details:
POST Request with Fetch API?
To process the request in Express, as mentioned in your comment assuming your express server is setup to parse body requests, you can do this:
app.post('/your/route', function(req, res) {
var name= req.body.name;
var password = req.body.password;
// ...do your bidding with this data
});

Sending binary through HTTP with React-Native Fetch API

Is there a way to use the Fetch API to upload a binary file (for instance to S3 using a signed URL) ?
That would be a simple PUT for some 'application/octet-stream'.
The XHR library is working, but I believe Fetch is better, especially in a React-Native environment.
Does React-Native Fetch support Blob nowadays?
Ideally I would like to do something like this, but Blob is undefined:
fetch('https://s3.amazonaws.com/signedUrl/', {
method: 'PUT',
headers: {
'Content-Type': 'application/octet-stream',
},
body: Blob(filePath)
})
This works on Android/iOS and simulators, if you have the file system path to your binary, such as an image using the built-in XMLHttpRequest to send requests:
const xhr = new XMLHttpRequest();
xhr.open('post', serviceUrl);
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
resolve(xhr.response);
} else {
reject(xhr.response);
}
}
};
xhr.setRequestHeader('Content-Type', 'image/jpeg');
xhr.send({ uri: 'pathToFile', type: 'image/jpeg', name: 'file' });
A sample pathToFile on macOS is file:///Users/username/Library/Developer/CoreSimulator/Devices/061D4A47-6363-4996-A157-03E6AD2DD9E4/data/Containers/Data/Application/3900F3EF-3259-43CF-9400-87B638EF9A1B/Library/Caches/Camera/F86E7345-080A-4D51-A80E-0CAD3370A353.jpg
I would recommend to use: https://github.com/github/fetch as polyfill for Fetch since is not widely supported.
Fetch documentation sample:
var input = document.querySelector('input[type="file"]')
var data = new FormData()
data.append('file', input.files[0])
data.append('user', 'hubot')
fetch('/avatars', {
method: 'POST',
body: data
})
I am using it as follows:
var input = document.querySelector('input[type="file"]')
function upload(e) {
const file = input.files[0];
const reader = new FileReader();
reader.onload = (e) => {
fetch('/avatars', {
method: 'POST',
body: e.currentTarget.result
})
};
reader.readAsArrayBuffer(file);
}
input.addEventListener('change', upload, false)

Resources