Extracting data from a fetch() in Javascript - javascript

I have a simple fetch request like this:
fetch('/data', {method: 'POST', credentials: 'same-origin', body: {'name': 'alice'}}).then(function(response){
console.log('reply:');
console.log(response);
});
Basically it should send a POST request to the local address /data with some parameters in it (same thing as an HTML form does) and then return the reply it gets (the /data page simply prints out "this is a test response")
But when I look at the console.log(response); it looks like this:
Response { type: "basic", url: ".../data", redirected: false, status: 200, ok: true, statusText: "OK", headers: Headers, bodyUsed: false }
The actual string returned by the page /data ("this is a test response") is nowhere to be found.
So how can I retrieve the actual returned string then?

To read the body of the response, you need to actually do that. See the details on MDN (here, here, and here), but in brief, if you want the body as text, then:
fetch(/*...*/)
.then(function(response) {
return response.text();
})
.then(function(responseText) {
// ...
});

Related

How handle errors with JS fetch again Laravel Api

My Goal
I would like to display the error messages in the Form. But for this I would need to have access to the JSON?
Code
HTML blade
<form>
<input name="name">
<p class="text-red-500 text-xs italic">Please fill out this field.</p> {{-- $message --}}
<button id="submit">SUBMIT</button>
</form>
javascript
<script>
const submitBtn = document.getElementById('submit');
submitBtn.addEventListener('click', (e) => {
e.preventDefault();
const fel = document.getElementById('commentForm');
const formData = new FormData(fel);
const url = '/api/comments';
let fetchData = {
method: 'POST',
body: formData,
headers: new Headers()
}
fetch(url, fetchData)
.then(response => {
if (!response.ok) {
return Promise.reject(response);
}
return response.json();
})
.then(data => {
console.log("Success");
console.log(data);
})
.catch(error => {
if (typeof error.json === "function") {
error.json().then(jsonError => {
console.log("Json error from API");
console.log(jsonError);
}).catch(genericError => {
console.log("Generic error from API");
console.log(error.statusText);
});
} else {
console.log("Fetch error");
console.log(error);
}
});
</script>
Response after a faulty request
HttpStatus: 400
// console.log(res) output
Response { type: "basic", url: "http://127.0.0.1:8000/api/comments", redirected: false, status: 400, ok: false, statusText: "Bad Request", headers: Headers, body: ReadableStream, bodyUsed: false }
​
body: ReadableStream { locked: false }​
bodyUsed: false​
headers: Headers { }​
ok: false​
redirected: false​
status: 400​
statusText: "Bad Request"​
type: "basic"​
url: "http://127.0.0.1:8000/api/comments"
​
<prototype>: ResponsePrototype { clone: clone(), arrayBuffer: arrayBuffer(), blob: blob(), … }
repellendus-dolor-quibusdam-sint-qui-news:147:29
Problem
In the Devtool Network tab, when I go to response of the request, I get a JSON
JSON: {"comment_content":["The comment content field is required."],"comment_name":["The comment name field is required."]}
When I output res.json() via the console within my fetch method, I get a Promise:
XHRPOSThttp://127.0.0.1:8000/api/comments
[HTTP/1.1 400 Bad Request 100ms]
Promise { <state>: "pending" }​
<state>: "fulfilled"​
<value>: Object { comment_content: (1) […], comment_name: (1) […] }​​
comment_content: Array [ "The comment content field is required." ]​​
comment_name: Array [ "The comment name field is required." ]​​
<prototype>: Object { … }
Additional question:
Is there a better way to display the errors from the response in the form? Maybe with the help of the form data object?
Considering you are making the request from JavaScript means you will also need to update the UI to reflect any error states. This includes targeting the right input elements based on the validation errors and appending them to the DOM. There may be libraries which can make this easier on the JS side but ultimately, you will need to write this logic.
As an aside, if you were using a traditional POST request, Laravel provides the $errors variable and #error blade directive. These help check for / display validation errors and are available in your application views. Since you are using blade, you may want to consider this.

Using HTTP in NativeScript to send Post-data to a TYPO3-Webservice

I'm trying to send form data from a NativeScript app to a TYPO3-Webservice.
This is the JavaScript I'm using:
httpModule.request({
url: "https://my.domain.tld/webservice?action=login",
method: "POST",
headers: { "Content-Type": "application/json" },
content: JSON.stringify({
username:username,
password:password
})
}).then((response) => {
console.log("got response");
console.log(response.content);
//result = response.content.toJSON();
callback(response.content.toJSON());
}, (e) => {
console.log("error");
console.log(e);
});
But I can't read this data in the controller. Even with this:
$rest_json = file_get_contents("php://input");
$postvars = json_decode($rest_json, true);
$postvars is empty. $_POST is empty, too (which is - according to some docs - because the data is sent as JSON and thus the $_POST-Array isn't populated.
Whatever I do, whatever I try, I can't get those variables into my controller.
I tried it with fetch as well as with formData instead of JSON.stringify, same result.
I might have to add, that when I add the PHP-part in the index.php of TYPO3, $postvars is being populated. So I guess something goes missing, until the controller is called.
Any ideas?
the nativescript part seems ok, your problem must be corrected in the server side.
i use similare call and its works
// send POST request
httpModule.request({
method: "POST",
url: appSettings.getString("SERVER") + '/product/list',
content: JSON.stringify(data),
headers: {"Content-Type": "application/json"},
timeout: 5000,
}).then(response => { // handle replay
const responseAsJson = response.content.toJSON();
console.log('dispatchAsync\n\tresponse:', responseAsJson);
}, reason => {
console.error(`[ERROR] httpModule, msg: ${reason.message}`);
});

Error sending Content_Tags while posting a video using FB API

I have tried many different ways but to no avail
API Spec - https://developers.facebook.com/docs/graph-api/reference/page/videos/
Param - content_tags ( list ) --> is what required
Below is my form data that is being posted
const formData = {
file_url: postOptions.filepath,
title: postOptions.title,
description: postOptions.description,
content_tags: ['tags', 'hello', 'hi']
};
HTTP Request Options
const options = {
url: https://graph-video.facebook.com/v9.0/${pageId}/videos?access_token=${accessToken},
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data',
'Cache-Control': 'no-cache',
Connection: 'keep-alive',
},
formData,
};
Error response returned.
{"error":
{
"message":"(#100) Param content_tags[0] must be a valid ID string (e.g., \"123\")",
"type":"OAuthException",
"code":100,
"fbtrace_id":"ANoCbTSnh4uL960SjyE6XBV"
}
}
As per documentation, seems it has to be not just any string but NUMBER string which are predefined IDs of the tag list<numeric string>
From documentation
Tags that describe the contents of the video. Use search endpoint with type=adinterest to get possible IDs.
Example:
~~~~
/search?type=adinterest&q=couscous
~~~~
Here's full path of the above example shown by facebook, how you can get some IDs:
https://graph.facebook.com/search?type=adinterest&q=​"home"&limit =10&access_token={{access_token}}

Cache Storage API, can't get header back

I would like to a check for max-age so I remove items from cache when they get old, but I can't get my own header back for some reason.
export function cacheResponse(url, response) {
caches.open('my-cache').then(function(cache) {
cache.put(url, new Response(JSON.stringify(response), {
headers: {
'Cache-Control': 'max-age=1',
'Content-Type': 'application/json;charset=UTF-8'
}
}));
});
}
cacheResponse('/hello', {hello: "world"})
I can see this working in the Application tab in chrome and I can see those 2 headers in the preview, but when I pull the item back out the headers object is null.
cache.match(url).then(async function(object) {
console.log(object.headers) // null
var body = await object.clone().json(); // {hello: "world"}
})
The object looks like this
object: Response
body: ReadableStream
bodyUsed: false
headers: Headers
__proto__: Headers
ok: true
redirected: false
status: 200
statusText: ""
type: "default"
url: ""
Seems like I should be able to lookup the headers from calling match() no?
That should work; you should be able to call response.headers.get('cache-control') to retrieve the value (assuming this is a same-origin response).
Here's a snippet of code that I just tested which worked when run in the JS console:
async function test() {
const constructedResponse = new Response('test', {
headers: {'cache-control': 'max-age=1'}
});
const cache = await caches.open('test');
cache.put('/test', constructedResponse);
const matchedResponse = await cache.match('/test');
console.log(`cache-control: ${matchedResponse.headers.get('cache-control')}`);
}

Alternative headers to "application/x-www-form-urlencoded"

So I have a funny little problem.
When calling my API from an AngularJS client with the following code, everything works fine, except that my API only recieves an empty object as data:
var req = {
method: 'Post',
url: config.API + request.toLowerCase() + '/',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
data: data
}
$http(req)
.then(function(response){
// handling response
})
Now, if I remove the headers: { 'Content-Type': 'application/x-www-form-urlencoded' } or changes it to headers: { 'Content-Type': 'application/json' } I get the this error:
The requested resource does not support http method 'OPTIONS'
My API controller looks like this:
[EnableCors("*", "*", "*")]
[HttpPost]
public string Post([FromBody]dynamic value)
{
// Do some stuff
Response response = new Response();
return JsonConvert.SerializeObject(response);
}
What I'm looking for is a way to prevent the tiresome "OPTIONS not supported" error, and still be able to send dynamic data to my controller
EDIT
Regarding the duplicate, I've already tried their approach, hence why I already are using [EnableCors] in my controller. But if I add this:
public static void Register(HttpConfiguration config)
{
config.EnableCors();
}
I get this error instead
Response to preflight request doesn't pass access control check: The
'Access-Control-Allow-Origin' header contains multiple values '*, *',
but only one is allowed. Origin 'http://localhost:82' is therefore not
allowed access

Categories