Problems passing parameters through the put method using fetch - javascript

I'm having problems trying to pass parameters by the put method using fetch
For this I am trying the following
fetch(`brands/${id}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({name: 'dummy text'})
})
.then(response => response.json())
.then(json => {
if (json.status === 'ok') {
// do some relevant logic
return false;
}
showErrors(json.errors);
})
.catch(error => console.error(error.message));
I am also trying using the FormData interface
const formData = new FormData();
formData.append('name', 'some dummy text');
fetch(`brands/${id}`, {
method: 'PUT',
body: formData
})
.then(response => response.json())
.then(json => {
if (json.status === 'ok') {
// Some relevant logic
return false;
}
showErrors(json.errors);
})
.catch(error => console.error(error.message));
But I am getting the same result (name parameter is not in the controller)
Inspected the network tab I can see that ajax has been called and in the params tab I can see that the variables are passed. But when trying to access these parameters from the controller they do not appear.
I appreciate your help
In backend when printing the parameters received in this query, the name parameter is not listed.
In backend the relevant parts in the controller definition are the following
The update method can only be invoked through the put method
static allowedMethods = [
save: 'POST',
update: 'PUT'
]
Here I hope that the name parameter has a value, but the parameter does not exist
def update() {
try {
Brand brand = brandService.update(params.id, params.name)
render(contentType: 'application/json') {
[status: 'ok', brand: brand]
}
} catch(ValidationException e) {
render(contentType: 'application/json') {
[status: 'fail', errors: e.errors]
}
}
}

Running your form through this little helper might do the trick:
form2Obj(form) {
const obj = {};
new FormData(form).forEach((val, key) => obj[key] = val);
return obj;
}

Related

How should PHP receiving end look like when using JS Fetch

just a quick question.
eventReceive: function(info) {
//get the bits of data we want to send into a simple object
var eventData = {
title: info.event.title,
start: info.event.start,
};
//send the data via an AJAX POST request, and log any response which comes from the server
fetch('<?php \E::get('obj_curr_module')->build_action_path('dev_guideline_ui_calendar','add_event'); ?>', {
method: 'POST',
headers: {
'Accept': 'application/json'
},
body: encodeFormData(eventData)
})
.then(response => console.log(response))
.catch(error => console.log(error));
},
My eventData is set as JS format. After using the function encodeFormData, i was wondering how should my php receiving end file looks like in order to retrieve the eventData pass on in the body?
My encodeFormData function is as below,
const encodeFormData = (data) => {
var form_data = new FormData();
for (var key in data) {
form_data.append(key, data[key]);
}
return form_data;
};

Problem with a 'double fetch' call in React Native

I am having problems using 'nested' Fetch calls within a React Native function. It seems the first Fetch works correctly, however an error is thrown on the second. Here is the code:
//****CALL TWO FETCH REQUESTS...
const data = { passkey: '12345', callup: 'name' };
const secondary = { passkey: '12345', callup: 'name' };
fetch('https://myremoteserveraddress', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
})
.then(function(response) {
if (response.ok) {
return response.json();
} else {
return Promise.reject(response);
}
})
.then(data => {
// Store the post data to a variable
_post = data;
console.log('Success on FIRST FETCH:', data);
console.log('answer is:', data.answer);
console.log('answer is:', _post.answer);
// Fetch another API
fetch('https://myremoteserveraddress', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(secondary),
})
})
.then(function (response) {
if (response.ok) {
return response.json();
} else {
return Promise.reject(response);
}
})
.then(function (userData) {
console.log('Returned from BOTH fetch calls'); //does not write to console
console.log(_post, userData); //does not write to console
this.vb.start();
})
.catch((error) => {
console.error('Error in onPressPublishBtn:', error);
});
//****
It seems the second Fetch call returns 'undefined', despite being identical to the first Fetch call which seems to work successfully. The error returned is "TypeError: undefined is not an object (evaluating 'response.ok')". If anybody can advise on what the problem may be I would be greatly appreciative. Thank you in advance.
You should return a Promise from the second then(...) block so that the response is passed to the third then(...) block. You might want to try something like this:
// Fetch another API
return fetch('https://myremoteserveraddress', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(secondary),
})

How to pass an argument to a function in my backend using .fetch()? ReactJS + Node

So I want to pass an integer argument to a function in my backend and have it return the data. I've been looking through the documentation and it seems like there might not be a way for me to pass an argument via the code I currently have. I just want second opinions before I consider using a different approach.
Frontend:
//is there a way for me to pass num to req in the backend?
newMarker = (num) => {
fetch('/api/getMarkers')
.then(res => res.json())
.then(mark => this.setState({ markers: mark }))
}
Backend:
//function where argument needs to be passed to, used in the request below
const fillNewMarker = async function fillNewMarker(num){
let temp;
let data;
await populartimes(markers[num].placeID)
.then(out => {data = out; temp = 'Currently ' + data.now.currently + ' full.'})
.catch(() => {temp = 'There is currently no data available.'});
markers[num].busy = temp;
}
//request
//i need num to be passed to req here
app.get('/api/newMarker', async (req,res) => {
await fillNewMarker(req);
console.log('Retrieve Data For New Marker Complete')
var mark = markers;
res.json(mark);
console.log('Sent Markers');
console.log(markers);
})
I've been working for quite a while so my brain is a little bit fried, there might be a really obvious solution that I have missed - if so, I apologize for my ignorance. Help is appreciated! TIA :)
Fix Attemp #1:
//Front end
newMarker = (num) => {
fetch('/api/newMarker', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
// 'Content-Type': 'application/x-www-form-urlencoded',
},
body: JSON.stringify(num) // body data type must match "Content-Type"
header
})
.then(res => res.json())
.then(mark => this.setState({ markers: mark }))
}
//method call via button
onButtonClick(){
this.newMarker(6)
//6 for testing
}
//backend
app.get('/api/newMarker', async (req,res) => {
console.log('Request received')
await fillNewMarker(req.body.num);
console.log('Retrieve Data For New Marker Complete')
var mark = markers;
res.json(mark);
console.log('Sent Markers');
console.log(markers);
})
You can pass an argument to fetch in the form of an object like
const response = await fetch('/api/getMarkers', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
// 'Content-Type': 'application/x-www-form-urlencoded',
},
body: JSON.stringify(num) // body data type must match "Content-Type" header
});
mark = await response.json();
this.setState({ markers: mark })
On backend receive the argument as req.body.arg_name
,In your case it would be req.body.num

in Vue PUT POST DELETE method showing not allowed when middlewear included

I am trying to implepement vue in my laravel application. Simple CRUD. The fetching and showing of data is working fine, but edit, delete, add is not. It is working if there is no auth checking middlewear in feedController. Need to make it work while the middlewear included.
Here is my add method:
fetch('api/feed', {
method: 'post',
body: JSON.stringify(this.feed),
headers: {
'content-type': 'application/json'
}
})
.then(res => res.json())
.then( data=> {
this.feed.title = '';
this.feed.body = '';
alert('Feed Added');
this.fetchFeeds();
})
Here is my delete method:
deleteFeed(id){
if (confirm('Are you sure you want to delete?')){
fetch(`api/feed/${id}`, {
method: 'delete'
})
.then(res => res.json())
.then(data=> {
alert('Article Removed');
this.fetchFeeds();
})
.catch(err => console.log(err));
}
}
Here are the routes in api.php
/Create new feed
Route::post('feed', 'FeedController#store');
//Update feed
Route::put('feed', 'FeedController#store');
//Delete feed
Route::delete('feed/{id}', 'FeedController#destroy');
And finally here is the controller's functions where the middlewear is.
For adding:
public function store(Request $request)
{
$feed = $request->isMethod('put')?Feeds::findOrFail($request->feed_id):new Feeds;
$feed->id= $request->input('feed_id');
$feed->title= $request->input('title');
$feed->body= $request->input('body');
// $feed->image= "Test Image String";
// $feed->link="Test Link String";
// $feed->user_id=4;
if($feed->save())
{
return new FeedResource($feed);
}
}
For deleting:
public function destroy($id)
{
$feed = Feeds::findOrFail($id);
if ($feed->delete()){
return new FeedResource($feed);
}
}

antd upload api: how to return promise

I am working with antd framework and I have to use upload API.
This is the signature:
action: Uploading URL : string|(file) => Promise
I am invoking the API in this way trying to return a Promise:
<Upload {...propsUpload}>
<Button> <Icon type="upload" />Upload</Button>
</Upload>
with propsUpload that refers to function uploadMedia
const propsUpload = {
action: this.uploadMedia,
listType: 'picture',
defaultFileList: [],
className: 'upload-list-inline',
};
and this is the function uploadMedia
uploadMedia = (file) => {
let formData = new FormData();
formData.append('file', file);
formData.append('uuid', this.generateuuid());
formData.append('domain', 'POST');
formData.append('filename', file.name );
return fetch(process.env.REACT_APP_API_URL +
'/v100/media/upload', {
method: 'POST',
credentials: 'include',
headers: {
Accept: 'application/json'
},
body: formData
})
.then(response => response.json())
.then(data => data.data)
.catch(error => {
console.log('Error fetching profile ' + error)
})
}
The file is uploaded to server correctly.
But after the call to API, antd try to do another call that fails, maybe because I am not returning the correct value from function.
As result the thumbnail is displayed with red border and and error is shownd. In the image below there are both (the call that fails and image with red border)
What type of object I have to return in function uploadMedia to use api correctly?
Thanks
I haven't used antd but looking at the docs of Uplaod component I think you're using it wrong. Look at the examples there and see the code, action expects either a URL or a Promise that will return this URl. And Upload in this case will make request itself, so you don't need to do fetch. And your promise returns the data (object) so the Upload sends the request to [object Object] (which is what's returned by .toString() when applied to an object in JS)
EDIT
Try to check all examples in docs, I can see that there is an example when you want to manually upload the file (if you really need it)
For anyone looking to access the response object after calling the API. There are two ways you can get access to the response.
Implement a custom API request mentioned as in other answers for this question.
Use the onChange method provided by AntD (Which is the easier than utilizing the custom request)
I will explain the second approach below using a code block.
const fileUploadProps = {
name: "file",
action: config.remote + "api/file",
method: "POST",
showUploadList: false,
headers: {
authorization: "authorization-text",
contentType: "multipart/form-data"
},
onChange(info) {
if (info.file.status === "done") {
const { response } = info.file;
updateProfile(response.payload.file);
} else if (info.file.status === "error") {
message.error("Error uploading the file");
props.endLoad();
}
},
beforeUpload(file) {
const isJpgOrPng = file.type === "image/jpeg" || file.type === "image/png";
if (!isJpgOrPng) {
message.error("You can only upload JPG/PNG file!");
}
const isLt2M = file.size / 1024 / 1024 < 2;
const isGT20K = file.size / 1024 > 20;
if (!isLt2M) {
message.error("Image must smaller than 2MB!");
}
if (!isGT20K) {
message.error("Image must larger than 20KB!");
}
if (isJpgOrPng && isLt2M && isGT20K) {
props.startLoad();
return true;
} else {
return false;
}
}
};
In Render function I have the AntD upload component
<Upload {...fileUploadProps}>
<Button icon={<CameraFilled style={{ fontSize: "30px" }} />}></Button>
</Upload>
You can notice how I got the access to the response object inside onChange function.
Once the upload is complete it will call the onChange function having response object inside the info object.
So from there you can get access to your data object easily and call the next method.
I solved using api customRequest in this way:
uploadMedia = (componentsData) => {
let formData = new FormData();
formData.append('file', componentsData.file);
formData.append('uuid', this.generateuuid());
formData.append('domain', 'POST');
formData.append('filename', componentsData.file.name );
fetch(process.env.REACT_APP_API_URL + '/v100/media/upload', {
method: 'POST',
credentials: 'include',
headers: {
Accept: 'application/json'
},
body: formData
})
.then(response => response.json())
.then(data => data.data)
.then(data=> componentsData.onSuccess())
.catch(error => {
console.log('Error fetching profile ' + error)
componentsData.onError("Error uploading image")
})
}
For those who are not clear how to actually implement it (and it is unclear in docs):
Just implement a customRequest function in the props that accepts two callbacks, which are onError and onSuccess, and other data such as file and filename.
Like this
const props = {
customRequest: (componentsData) => {
let formData = new FormData();
formData.append('file', componentsData.file);
formData.append('uuid', this.generateuuid());
formData.append('domain', 'POST');
formData.append('filename', componentsData.file.name );
fetch(process.env.REACT_APP_API_URL + '/v100/media/upload', {
method: 'POST',
credentials: 'include',
headers: {
Accept: 'application/json'
},
body: formData
})
.then(response => response.json())
.then(data => data.data)
.then(data=> componentsData.onSuccess())
.catch(error => {
console.log('Error fetching profile ' + error)
componentsData.onError("Error uploading image")
})
}
}
And let Upload component receive the props.
const App = () => {
return <Upload {...props} />
}

Categories

Resources