Changing JSON values with fetch - javascript

Hey guys I'm writing a small email app and I am trying to create an archive button for each email. I'm sure that the function is being called but, for some reason, it's not changing archived to true.
The odd thing is, if I replaced "archived: true" with "read: true" it does change 'read' to true. However, for some reason it won't change the archived attribute.
I'm sure that 'archived' is a valid attribute in the JSON API.
Any reason this would happen? Here is the code in question:
function archive_email(id) {
fetch('/emails/' + id, {
method: 'PUT',
body: JSON.stringify({
archived: true
})
})
load_mailbox("inbox");
}

I think is a promise problem, did you try the following code?
function archive_email(id) {
fetch('/emails/' + id, {
method: 'PUT',
body: JSON.stringify({
archived: true
})
}).then(() => {
load_mailbox("inbox");
})
}

Related

Axios get call in Vue3 not working, although curl and javascript work as expected

I'm trying to make an API call from my Vue3 app. The prepared API has an endpoint like http://localhost:8888/api/dtconfigsearch, where one needs to pass a json payload like { "Modelname": "MyFancyModel"} to get the full dataset with the given modelname. Pure get functions without a payload / a body do work from my Vue3 project to the golang backend, but I'm having problems with passing a payload to the backend.
Test with curl -> ok
$ curl -XGET localhost:8888/api/dtconfigsearch -d '{"Modelname" : "MyFancyModel" }'
{"ID":4,"Modelname":"MyFancyModel","ModelId":"96ee6e80-8d4a-b59a-3524-ced3187ce7144000","OutputTopic":"json/fancyoutput"}
$
This is the expected output.
Test with javascript ok
Source file index.js:
const axios = require('axios');
function makeGetRequest() {
axios.get(
'http://localhost:8888/api/dtconfigsearch',
{
data: { Modelname : "MyFancyModel" },
headers: {
'Content-type' : 'application/json'
}
}
)
.then(resp => {
console.log(resp.data)
})
.catch(err => {
console.log(err)
})
}
makeGetRequest()
Output
$ node index.js
{
ID: 4,
Modelname: 'MyFancyModel',
ModelId: '96ee6e80-8d4a-b59a-3524-ced3187ce7144000',
OutputTopic: 'json/fancyoutput'
}
$
Here, I also get the desired output.
Test within Vue fails :-(
Source in the Vue one file component:
onSelection(event) {
let searchPattern = { Modelname : event.target.value }
console.log(event.target.value)
console.log("searchPattern = " + searchPattern)
axios.get("http://localhost:8888/api/dtconfigsearch",
{
data : { Modelname : "Windshield"},
headers: {
'Content-type' : 'application/json',
'Access-Control-Allow-Origin': '*'
}
})
.then(response => {
console.log(response.data)
})
.catch(err => {
console.log(err)
alert("Model with name " + event.target.value + " not found in database")
})
},
Output in browser:
In the image you can see in the terminal log on the right side that the backend is not receiving the body of the API call. However, in the browser information of the call there is content in the config.data part of the object tree, which is the payload / the body. The only thing that bothers me that it is not a json object, but stringified json, although it was entered as json object. According to the documentation, the parameter name (data) in the call should be correct to hold the body content of the api call.
I've tried different header information, looked if it could be a CORS issue, what it isn't to my opinion, exchanged key data with body, used axios instead of axios.get and adapted parameter, all without success. The version of the axios library is 0.27, identical for Vue and vanilla javascript. After checking successfully in javascript, I was sure that it would work the same way in Vue, but it didn't.
Now I'm lost and have no further ideas how to make it work. Maybe someone of you had similar issues and could give me a hint? I'd be very grateful for some tipps!!

Syntax for correct Routes path

So I have a component for displaying players which uses my displayPlayerObject function. The problem is it is I do not have the correct route for fetching in the function and for POST in my routes.rb. The model relationships have the players belonging to the teams and the route for getting a player is "http://localhost:3000/api/teams/1/players/1" 1 being the team id for the former and player id in the latter. But how do I make the displayPlayerObject work the same way syntax wise? And how should it look like for the POST in routes.rb? Also I suspect my players controller's 'show' is wrong as well.
displayPlayerObject function (edited):
export const displayPlayerObject = (id, teamId, type) => {
return dispatch => {
const data = { id };
fetch(`/api/teams/:team_id/players/show`, {
method: 'post',
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
body: JSON.stringify(data)
})
.then(res => res.json())
.then(responseJSON => { dispatch({ type , player_object: responseJSON})
})
}
};
My routes.rb (edited):
Rails.application.routes.draw do
scope '/api' do
post "teams/show", to: 'teams#show'
post "teams/:team_id/players/show", to: 'players#show'
resources :teams do
resources :players
resources :star_players
end
end
end
Players Controller Show (edited):
def show
Player.find(params[:id])
render json: #player, status: 200
end
Let's make it look better.
First of all Player.find_by(id: params[:id]) is nonsense, since find_by(id: params[:id]) is equal to where(id: params[:id]).take. Better to replace it with classic find(params[:id]) which looks much better.
What about your main question, what is the point to give name for POST with displayObject. For me display something means GET it to me. If you want to get some player you need to call api/teams/:team_id/players/:id. But if you want to create new player you need to make POST request to /api/teams/:team_id/players route.
P.S.1 Just change request method from POST to GET. And then add to your promise this:
.then(res => {
console.log(res)
})
And observe what server returns
P.S.2 Change request to
fetch(`/api/teams/:team_id/players/:id`)
And in controller find player by :id

Failed to execute 'fetch' on 'Window': Request with GET/HEAD method cannot have body in react-admin

I am using react-adminframework, and I have written my own DataProvider. I am trying to accomplish that when an User is created, an instance of UserPossession is created as well. My code bellow accomplishes that, but react-admin Front-end just displays the warning message:
Failed to execute 'fetch' on 'Window': Request with GET/HEAD method cannot have body
I checked the Network tab in Developer Tools and every request to server is correct, there is no error. Which leaves me confused and stuck with this, because I have no idea what that warning means or why is it even occuring.
My code is a part of convertDataRequestToHTTP constant and looks like this:
if (resource === 'User') {
url = `${apiUrl}/${resource}`;
options.body = params.data;
httpClient(url, {
method: 'POST',
body: JSON.stringify(options.body),
})
.then(response => (
url = `${apiUrl}/Location`,
options.method = 'POST',
options.body = JSON.stringify({
"odata.type": "HardwareDatabase.UserPossession",
"Name": response.json.Login,
"UserId": response.json.Id
}),
httpClient(url, {
method: options.method,
body: options.body
})
));
}
If you have any questions regarding the code I can clarify.
Thank you for any ideas in advance.
Since you are stating that this code snippet is a part of convertDataRequestToHTTP I might see the issue. httpClient cannot be used in this constant since it creates duplicit calls to API or in your case, this Warning. Correct way would be to only state the options constant.
url = `${apiUrl}/${resource}`;
options.body = JSON.stringifiy(params.data);
options.method = 'POST';
Later in the constant that converts response from OData to mandatory React Admin format, state the httpClient.
params.data = {
"odata.type": "HardwareDatabase.UserPossession",
"Name": response.json.Login,
"UserId": response.json.Id
};
httpClient(`${apiUrl}/Location`, {
method: 'POST',
body: JSON.stringify(params.data),
})
Unfortunately, the GET method for XMLHttpRequest and fetch don't support request bodies.
A temporary work around I found was to use the axios library, which does let you send GET with request bodies.
const res = await axios.get("/api/devices", {
data: { deviceName: 'name' }
})

React get and show attached files in Rails

seems a simple problem but, i don't know why this is causing a little stress, anyway.
here is situation:
after get the attachments on the Post.show in rails
async getAttachments() {
// this.setState({showProgress: true})
let auth_token = window.localStorage.getItem("auth_token");
let post_id = this.props.match.params.id;
fetch(`/posts/${post_id}/attachments`, {
method: "GET",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
Access: auth_token
}
})
.then(response => response.json())
.then(json => {
this.setState({
attachments: json.attachments,
image: json.attachments.image,
thumb: json.attachments.image.thumb,
url: json.attachments.thumb.url
});
})
.catch(error => {
console.error(error);
});
}
i decide to render it as usual
with {this.state.attachments}
but did not rendered.
so i tried to map and then i tried
var attachments = this.state.attachments.map(a => {
return (
<div key={a.id}>
<img source={a.thumb} />
<img source={a.url}>{a.url}</img>
</div>
);
});
the thing is ever rails carrierwave attachment/files. create a object inside the array and many people still have doubt how to grab and render these files.
The HTML image tag uses an attribute named src, not source. That's your problem.
Aside: Consider this snippet of your code:
this.setState({
attachments: json.attachments, // OK, keep
image: json.attachments.image, // bad path into the object
thumb: json.attachments.image.thumb, // bad path into the object
url: json.attachments.thumb.url // bad path into the object
});
The three lines starting with image, thumb, and attachment should be deleted.
The result of using the code without deleting those lines will be that your state looks like:
{
attachments: <an array of attachments>, // correct, wanted, should keep
image: undefined,
thumb: undefined,
url: undefined
}
This is because json.attachments is an array so it does not have any data at the paths you are calling. By "path into the object" I merely mean a sequence of keys to call in sequence of dot notation.

Using API JSON data in react conditional return

I have a small (never for production) Express/React app, I'm validating a hashed pin in express and returning either message: false if validation fails or message: <cardnumber> if validation is succefull. In my react frontend I want to eventually redirect if it returns a cardnumber, but first I'm just trying to conditionally render a component.
I have a constructor for the json response
constructor() {
super();
this.state = {
cardnumber: '',
pin: '',
servercardnumber: {
message: ''
}
};
Then I'm getting the data from API like this
const url = '/api/login';
const serverResponse = await fetch(url, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': true
},
body: JSON.stringify(data)
});
const json = await serverResponse.json();
console.log(json);
this.setState(
prevState => {
return {
servercardnumber: json.cardnumber
};
},
() => {
console.log(this.state.cardnumber);
}
);
};
Then I'm trying to conditionally render a material ui component in my react return
render() {
const { cardnumber, pin, servercardnumber } = this.state;
return (
<React.Fragment>
<Card>{!servercardnumber ? <Card> Server says no</Card> : null}</Card>
{console.log('server says:')}
{console.log(servercardnumber)}
The {console.log(servercardnumber)} first returns the correct servercardnumber, then returns undefined.
What I need is to see the response in my conditional render, and show the rendered component if login is succefull (or show if not succefull, as long as I get it to conditionally render)
I've done a bunch of changes to this code in my attempt to get this to work, so it may seem a bit cluttered.
Full front end code for the relevant file: https://pastebin.com/VbdzmE4E
Server code for the relevant file: https://pastebin.com/TZ35NZxa
Reposting my comment here so that it the question can be resolved.
The state property servercardnumber should be set to json.message instead of json.cardnumber.

Categories

Resources