Providing query string to fetch from a GraphQL API - fetch

I am attempting to fetch some data from a GraphQL endpoint, however I keep getting the error "Must provide query string". I am sure I am providing the query string, where does this error come from?
The endpoint is: https://antserver-blocjgjbpw.now.sh/graphql
const query = `{
ants {
name
color
length
weight
}
}`
document.getElementById("basicFetchButton").addEventListener("click", () => {
fetch("https://antserver-blocjgjbpw.now.sh/graphql", {
method: 'POST',
'Content-Type': 'application/graphql',
body: JSON.stringify({query})
})
.then(res => res.json())
.then(data => console.log(data))
})

In this case, you want to use Content-Type: 'application/json'. application/graphql requires the entire body of the request to be the query, but I don't recommend that approach since it's impossible to send query variables.
Here's a full code sample:
fetch('https://antserver-blocjgjbpw.now.sh/graphql', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query }),
})
.then(res => res.json())
.then(res => console.log(res.data));
For more examples, check out my article 4 simple ways to call a GraphQL API

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.

Cypress API testing. Can not find property

I am developing Cypress tests for my API.
The response from my API in Postman is below:
{"infected" : false}
And my Cypress test is below:
describe("Testing the result after scanning file", () => {
it("Scan file", function () {
//Declarations
const fileName = 'example.json';
cy.fixture(fileName, 'binary')
.then((file) => Cypress.Blob.binaryStringToBlob(file))
.then((blob) => {
const formData = new FormData();
formData.append("file", blob, fileName);
cy.request({
method: 'POST',
headers: {
'content-type': 'multipart/form-data'
},
body: formData,
url: '/scan'
}).then(response => {
console.log('the response is: ', response.body)
expect(response.body).to.have.property('infected').and.eq(false);
});
})
});
});
In my browser, the Cypress test fails with the message:
assert expected {} to have property infected
I really have already broken my brain with this issue and still have no clue how to tackle it. Can anybody give me an idea what is going wrong?
Try converting the response to json, you may be seeing a string version of the data.
Postman output will not be helpful, it could be converting automatically in the background.
cy.request({
...
})
.then(response => response.json())
// OR
// .then(response => response.body.json())
.then(data => {
console.log('the data is: ', data) // better debug tool than Postman
expect(data).to.have.property('infected').and.eq(false);
});

Where is fetch getting it's endpoint value from?

I have the following code, I am using React:
// post-post
const queryDatabase = (obj, endpoint) => {
console.log(obj);
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(obj)
};
console.log(endpoint);
fetch(endpoint, requestOptions)
.then(data => {return Promise.resolve(data)}
);
}
export {queryDatabase};
For some reason console.log(endpoint) prints the endpoint that I am passing in, e.g. "/users", "/profile" etc. However, fetch is trying to send to http://localhost:3000/users so when I try to manually pass in an endpoint I get an error about trying to post to http://localhost/http://localhost/users.
Where is fetch getting this default http://localhost:3000 value?
It's only doing this for POST requests.
The only environment variables are the following:
REACT_APP_AUTH0_REDIRECT_URI=http://localhost:3000
REACT_API_SERVER_URL=http://api.localhost
PORT=3000
I also have some other environment variables for Auth0, is Auth0 doing this? I've removed these variables for testing and still nothing.
The answer is to use the Request object and pass that through to fetch:
const requestOptions = new Request(serverUrl + endpoint, {
method: 'POST',
body: JSON.stringify(obj),
headers: new Headers({
'Content-Type': 'application/json'
})
});
Why bother... use axios or something else, fetch sucks.
EDIT:
Apparently not a problem with fetch. Whatever the case this is the fix.

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' }),
}

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

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
})

Resources