Performing POST method Using Axios and Pipe Function - javascript

So I am currently learning about FP and the use of the Pipe operator which combines n functions and simply calls it from left to right. Currently, I am trying to make a POST call using Axios and then handle the data returned appropriately, but then the pending promise value always results to undefined. Here is what my code looks like.
The pipe function
const pipe = (...fns) => (initValue) => fns.reduce((v, f) => f(v), initValue)
Here is the first function that is passed to the pipe function
const dataToPost = ({ title, body, userId }) => {
return {
method: 'post',
url: 'https://jsonplaceholder.typicode.com/posts',
data: {
title,
body,
userId,
},
headers: {
'Content-type': 'application/json; charset=UTF-8',
},
}
}
Here is how I implement the pipe function passing it the various arguments
const postTodoFunc = ({ pipe }) => {
return async function postTodo({ title, body, userId }) {
const callJSONAPI = pipe(dataToPost, axios, output) ///this line here
const calledFunc = await callJSONAPI({
title,
body,
userId,
})
return calledFunc
}
}
The output function looks like this.
const output = (response) => {
return response.data
}
The postTodoFunc is invoked like this
const postedTodo = postTodoFunc({ pipe })
const result = postedTodo({
title: 'Rule the world',
body: 'some random body',
userId: 1,
})
console.log(result) // undefined
Now from my understanding, the dataToPost function is called first which returns an object that is equivalent to this
{
method: 'post',
url: 'https://jsonplaceholder.typicode.com/posts',
data: {
title,
body,
userId,
},
headers: {
'Content-type': 'application/json; charset=UTF-8',
},
}
This object is then passed to axios which is then equivalent to the following format
axios({
method: 'post',
url: 'https://jsonplaceholder.typicode.com/posts',
data: {
title,
body,
userId,
},
headers: {
'Content-type': 'application/json; charset=UTF-8',
},
})
The response from this axios call returns undefined. Because I thought the response will be passed to the next function which is this case output function. But that does not seem to be the case. How can I fix this and get the correct data? Initially from the JSONPlaceholder website, the response is meant to be like this
{
id: 101,
title: 'Rule the world',
body: 'Some random body',
userId: 1
}
but then again, I am getting undefined after the pending promise.

Related

Return full data on JavaScript Promise for a function within a class while using node-client-ntlm

I have a function within a class that makes a call and returns a promise object with data. I do get the data back the issue is I cannot figure out how to make the call wait till all of the data is returned at the moment it only returns a few lines of data and cuts off the rest of the return.
async callCurl(postFields) {
this.postFields = postFields;
const response = await client
.request(
{
url: this.url,
method: "POST",
debug: true,
body: "folderGuid=" + this.postFields,
headers: {
"content-type": "application/x-www-form-urlencoded",
},
resolve: true,
},
"username",
"password",
"",
"domain"
)
.then((response) => {
console.log(response.body);
})
.catch(function (error) {
console.log(error);
});
//return response;
}

jQuery ajax call is returning response data as String instead of Object

On the following StackBlitz:
https://stackblitz.com/edit/react-jbthdw?file=src%2FApp.js
I have a code which fetches a JSON data with a list of names.
There are two ways of returning data: Axios and jQuery.
With the Axios approach the code works properly.
Now, because some business decisions I need to replace Axios with jQuery.
My problem is: with jQuery the response.data is fetched as string when it should be as object as it happens with Axios.
Below you have the code, but feel free to play with the StackBlitz playground I provided above:
import React from 'react';
import axios from 'axios';
import $ from 'jquery';
import './style.css';
export default () => {
const jsonSource = 'https://raw.githubusercontent.com/tlg-265/mockend/master/data.json';
const handleClickAxios = () => {
axios.get(jsonSource).then(response => {
console.log({ responseType: (typeof response.data)});
console.log(response.data);
});
};
const handleClickJQuery = () => {
sendApiRequest({ url: jsonSource, method: 'get' }).then(response => {
console.log({ responseType: (typeof response.data)});
console.log(response.data);
});
};
return (
<div>
<h1>Axios vs jQuery</h1>
<p><b>Inconsitency:</b> returning response as Object vs String</p>
<button onClick={handleClickAxios}>Axios</button>{' '}
<button onClick={handleClickJQuery}>jQuery</button>
</div>
);
};
export const sendApiRequest = ({
url,
method,
data,
timeout,
}) => {
method = method.toUpperCase();
let additionalSettings = { data: data };
if (method === 'POST') {
additionalSettings = {
contentType: 'application/json',
dataType: 'json',
data: JSON.stringify(data),
};
}
return new Promise((resolve, reject) => {
$.ajax({
url,
method: method,
timeout,
...additionalSettings,
success: (response) => {
resolve({
data: response
});
},
error: ({ responseJSON }) => {
reject(responseJSON);
},
});
});
};
Here you have a screenshot of the issue:
Any idea on what do I need to update on the code in order to get: response.data as object with jQuery? I need to get that without any post processing of the response. Is there maybe any params I could use with jQuery so it behaves similarly to Axios?
Thanks!
The URL you are requesting includes this response header:
content-type: text/plain; charset=utf-8
Which is why jQuery isn't processing it as JSON automatically.
A quick search of the documentation for the word "json" quickly brings up the dataType option which lets you override the content-type.
const jsonSource = 'https://raw.githubusercontent.com/tlg-265/mockend/master/data.json';
jQuery.ajax({
url: jsonSource,
dataType: 'json'
}).then(data => {
console.log({
responseType: (typeof data)
});
console.log(data);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Chaining an axios.get call to use the response for an axios.all multiple request

I'm having difficulties to understand how Shall I handle this type of calls. I need an initial axios.get call and loop through to make an axios.all call. This is my code:
export async function getServerSideProps(context) {
const axios = require("axios");
const options = {
method: 'GET',
url: 'xxxxx',
params: { id_user: 'xxxxx' },
headers: {
'X-RapidAPI-Host': 'xxxxxxx',
'X-RapidAPI-Key': 'xxxxxxx'
}
};
const res = axios.request(options).then(function (response) {
axios.all(response.data.users.map(user => {
axios.get('xxxxxxx', {
params: { response_type: 'short', ig: user.username, corsEnabled: 'true' },
headers: {
'X-RapidAPI-Host': 'xxxxx',
'X-RapidAPI-Key': 'xxxxxxx'
}
})
})).then(res => {
return res.data
})
})
const payload = await res;
I have an error on the page when I try to console log the payload. What's going worng with my call?
Looks like you need a return inside your map.
The below code worked for me and the unique params were updated on each request. Once you prepare your series of endpoints or whatever is unique for each request (user data per your sample code) you map over the relevant data and make all your get requests. The result returned will be an array of the responses you get back from each request once all of the requests have finished.
Regarding chaining together requests, you can use any number of .then() to kick off other actions. You mention needing an id from an initial get request, so here is a solution based on that example.
Hope you find it helpful.
const users = [{ username: '1' }, { username: '2' }, { username: '3' }];
axios
.get('https://jsonplaceholder.typicode.com/posts')
.then((res) => {
console.log(res);
// simulating getting some id you need...
const id = res.data[4].id;
console.log(id);
return id;
})
.then((id) => {
axios
.all(
users.map((user) => {
return axios.get('https://jsonplaceholder.typicode.com/posts', {
params: {
response_type: 'short',
// just an example of using id...
importantId: id,
ig: user.username,
corsEnabled: 'true',
},
headers: {
'X-RapidAPI-Host': 'xxxxxxx',
'X-RapidAPI-Key': 'xxxxxxx',
},
});
})
)
.then((res) => {
console.log(res);
});
});

How to pass data in body in get type Api in react.js?

I am trying to pass data in body of get type Api in react.js app.
I am using the following code. But Api doesn't get any data.
getUnits = ( key, text, code, limit, offset ) => {
let data = JSON.stringify( { unit: { key, text, code, limit, offset } } );
let config = {
method: 'get',
url: BaseURL + 'unit',
headers: { 'Content-Type': 'application/json' },
data: data
};
axios( config ).then( res => {
store.dispatch( {
type: GET_UNIT,
payload: res.data.units
} )
} ).catch( err => {
console.log(err);
})
})
}
Adding on what #Jayna commented, you can't send a body with a get request. You may do it on Postman and generate the axios code for it, but it won't work due to the XMLHTTPREQUEST javascript has. Body is ignored in get request by default
1You need to pass params instead like this:
let config = {
method: 'get',
url: BaseURL + 'unit',
headers: { 'Content-Type': 'application/json' },
params: {
field1: 'field1',
field2: 'field2'
}
};
So my suggestion is change your url on backend to accept query parameters and send the axios get request like this.

Fetch: POST JSON data

I'm trying to POST a JSON object using fetch.
From what I can understand, I need to attach a stringified object to the body of the request, e.g.:
fetch("/echo/json/",
{
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
method: "POST",
body: JSON.stringify({a: 1, b: 2})
})
.then(function(res){ console.log(res) })
.catch(function(res){ console.log(res) })
When using jsfiddle's JSON echo I'd expect to see the object I've sent ({a: 1, b: 2}) back, but this does not happen - chrome devtools doesn't even show the JSON as part of the request, which means that it's not being sent.
With ES2017 async/await support, this is how to POST a JSON payload:
(async () => {
const rawResponse = await fetch('https://httpbin.org/post', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({a: 1, b: 'Textual content'})
});
const content = await rawResponse.json();
console.log(content);
})();
Can't use ES2017? See #vp_art's answer using promises
The question however is asking for an issue caused by a long since fixed chrome bug.
Original answer follows.
chrome devtools doesn't even show the JSON as part of the request
This is the real issue here, and it's a bug with chrome devtools, fixed in Chrome 46.
That code works fine - it is POSTing the JSON correctly, it just cannot be seen.
I'd expect to see the object I've sent back
that's not working because that is not the correct format for JSfiddle's echo.
The correct code is:
var payload = {
a: 1,
b: 2
};
var data = new FormData();
data.append( "json", JSON.stringify( payload ) );
fetch("/echo/json/",
{
method: "POST",
body: data
})
.then(function(res){ return res.json(); })
.then(function(data){ alert( JSON.stringify( data ) ) })
For endpoints accepting JSON payloads, the original code is correct
I think your issue is jsfiddle can process form-urlencoded request only. But correct way to make json request is pass correct json as a body:
fetch('https://httpbin.org/post', {
method: 'POST',
headers: {
'Accept': 'application/json, text/plain, */*',
'Content-Type': 'application/json'
},
body: JSON.stringify({a: 7, str: 'Some string: &=&'})
}).then(res => res.json())
.then(res => console.log(res));
From search engines, I ended up on this topic for non-json posting data with fetch, so thought I would add this.
For non-json you don't have to use form data. You can simply set the Content-Type header to application/x-www-form-urlencoded and use a string:
fetch('url here', {
method: 'POST',
headers: {'Content-Type':'application/x-www-form-urlencoded'}, // this line is important, if this content-type is not set it wont work
body: 'foo=bar&blah=1'
});
An alternative way to build that body string, rather then typing it out as I did above, is to use libraries. For instance the stringify function from query-string or qs packages. So using this it would look like:
import queryString from 'query-string'; // import the queryString class
fetch('url here', {
method: 'POST',
headers: {'Content-Type':'application/x-www-form-urlencoded'}, // this line is important, if this content-type is not set it wont work
body: queryString.stringify({for:'bar', blah:1}) //use the stringify object of the queryString class
});
After spending some times, reverse engineering jsFiddle, trying to generate payload - there is an effect.
Please take eye (care) on line return response.json(); where response is not a response - it is promise.
var json = {
json: JSON.stringify({
a: 1,
b: 2
}),
delay: 3
};
fetch('/echo/json/', {
method: 'post',
headers: {
'Accept': 'application/json, text/plain, */*',
'Content-Type': 'application/json'
},
body: 'json=' + encodeURIComponent(JSON.stringify(json.json)) + '&delay=' + json.delay
})
.then(function (response) {
return response.json();
})
.then(function (result) {
alert(result);
})
.catch (function (error) {
console.log('Request failed', error);
});
jsFiddle: http://jsfiddle.net/egxt6cpz/46/ && Firefox > 39 && Chrome > 42
2021 answer: just in case you land here looking for how to make GET and POST Fetch api requests using async/await or promises as compared to axios.
I'm using jsonplaceholder fake API to demonstrate:
Fetch api GET request using async/await:
const asyncGetCall = async () => {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
const data = await response.json();
// enter you logic when the fetch is successful
console.log(data);
} catch(error) {
// enter your logic for when there is an error (ex. error toast)
console.log(error)
}
}
asyncGetCall()
Fetch api POST request using async/await:
const asyncPostCall = async () => {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
// your expected POST request payload goes here
title: "My post title",
body: "My post content."
})
});
const data = await response.json();
// enter you logic when the fetch is successful
console.log(data);
} catch(error) {
// enter your logic for when there is an error (ex. error toast)
console.log(error)
}
}
asyncPostCall()
GET request using Promises:
fetch('https://jsonplaceholder.typicode.com/posts')
.then(res => res.json())
.then(data => {
// enter you logic when the fetch is successful
console.log(data)
})
.catch(error => {
// enter your logic for when there is an error (ex. error toast)
console.log(error)
})
POST request using Promises:
fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
// your expected POST request payload goes here
title: "My post title",
body: "My post content."
})
})
.then(res => res.json())
.then(data => {
// enter you logic when the fetch is successful
console.log(data)
})
.catch(error => {
// enter your logic for when there is an error (ex. error toast)
console.log(error)
})
GET request using Axios:
const axiosGetCall = async () => {
try {
const { data } = await axios.get('https://jsonplaceholder.typicode.com/posts')
// enter you logic when the fetch is successful
console.log(`data: `, data)
} catch (error) {
// enter your logic for when there is an error (ex. error toast)
console.log(`error: `, error)
}
}
axiosGetCall()
POST request using Axios:
const axiosPostCall = async () => {
try {
const { data } = await axios.post('https://jsonplaceholder.typicode.com/posts', {
// your expected POST request payload goes here
title: "My post title",
body: "My post content."
})
// enter you logic when the fetch is successful
console.log(`data: `, data)
} catch (error) {
// enter your logic for when there is an error (ex. error toast)
console.log(`error: `, error)
}
}
axiosPostCall()
I have created a thin wrapper around fetch() with many improvements if you are using a purely json REST API:
// Small library to improve on fetch() usage
const api = function(method, url, data, headers = {}){
return fetch(url, {
method: method.toUpperCase(),
body: JSON.stringify(data), // send it as stringified json
credentials: api.credentials, // to keep the session on the request
headers: Object.assign({}, api.headers, headers) // extend the headers
}).then(res => res.ok ? res.json() : Promise.reject(res));
};
// Defaults that can be globally overwritten
api.credentials = 'include';
api.headers = {
'csrf-token': window.csrf || '', // only if globally set, otherwise ignored
'Accept': 'application/json', // receive json
'Content-Type': 'application/json' // send json
};
// Convenient methods
['get', 'post', 'put', 'delete'].forEach(method => {
api[method] = api.bind(null, method);
});
To use it you have the variable api and 4 methods:
api.get('/todo').then(all => { /* ... */ });
And within an async function:
const all = await api.get('/todo');
// ...
Example with jQuery:
$('.like').on('click', async e => {
const id = 123; // Get it however it is better suited
await api.put(`/like/${id}`, { like: true });
// Whatever:
$(e.target).addClass('active dislike').removeClass('like');
});
Had the same issue - no body was sent from a client to a server.
Adding Content-Type header solved it for me:
var headers = new Headers();
headers.append('Accept', 'application/json'); // This one is enough for GET requests
headers.append('Content-Type', 'application/json'); // This one sends body
return fetch('/some/endpoint', {
method: 'POST',
mode: 'same-origin',
credentials: 'include',
redirect: 'follow',
headers: headers,
body: JSON.stringify({
name: 'John',
surname: 'Doe'
}),
}).then(resp => {
...
}).catch(err => {
...
})
This is related to Content-Type. As you might have noticed from other discussions and answers to this question some people were able to solve it by setting Content-Type: 'application/json'. Unfortunately in my case it didn't work, my POST request was still empty on the server side.
However, if you try with jQuery's $.post() and it's working, the reason is probably because of jQuery using Content-Type: 'x-www-form-urlencoded' instead of application/json.
data = Object.keys(data).map(key => encodeURIComponent(key) + '=' + encodeURIComponent(data[key])).join('&')
fetch('/api/', {
method: 'post',
credentials: "include",
body: data,
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
})
The top answer doesn't work for PHP7, because it has wrong encoding, but I could figure the right encoding out with the other answers. This code also sends authentication cookies, which you probably want when dealing with e.g. PHP forums:
julia = function(juliacode) {
fetch('julia.php', {
method: "POST",
credentials: "include", // send cookies
headers: {
'Accept': 'application/json, text/plain, */*',
//'Content-Type': 'application/json'
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8" // otherwise $_POST is empty
},
body: "juliacode=" + encodeURIComponent(juliacode)
})
.then(function(response) {
return response.json(); // .text();
})
.then(function(myJson) {
console.log(myJson);
});
}
It might be useful to somebody:
I was having the issue that formdata was not being sent for my request
In my case it was a combination of following headers that were also causing the issue and the wrong Content-Type.
So I was sending these two headers with the request and it wasn't sending the formdata when I removed the headers that worked.
"X-Prototype-Version" : "1.6.1",
"X-Requested-With" : "XMLHttpRequest"
Also as other answers suggest that the Content-Type header needs to be correct.
For my request the correct Content-Type header was:
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"
So bottom line if your formdata is not being attached to the Request then it could potentially be your headers. Try bringing your headers to a minimum and then try adding them one by one to see if your problem is resolved.
If your JSON payload contains arrays and nested objects, I would use URLSearchParams and jQuery's param() method.
fetch('/somewhere', {
method: 'POST',
body: new URLSearchParams($.param(payload))
})
To your server, this will look like a standard HTML <form> being POSTed.
You could do it even better with await/async.
The parameters of http request:
const _url = 'https://jsonplaceholder.typicode.com/posts';
let _body = JSON.stringify({
title: 'foo',
body: 'bar',
userId: 1,
});
const _headers = {
'Content-type': 'application/json; charset=UTF-8',
};
const _options = { method: 'POST', headers: _headers, body: _body };
With clean async/await syntax:
const response = await fetch(_url, _options);
if (response.status >= 200 && response.status <= 204) {
let data = await response.json();
console.log(data);
} else {
console.log(`something wrong, the server code: ${response.status}`);
}
With old fashion fetch().then().then():
fetch(_url, _options)
.then((res) => res.json())
.then((json) => console.log(json));
**//POST a request**
const createTodo = async (todo) => {
let options = {
method: "POST",
headers: {
"Content-Type":"application/json",
},
body: JSON.stringify(todo)
}
let p = await fetch("https://jsonplaceholder.typicode.com/posts", options);
let response = await p.json();
return response;
}
**//GET request**
const getTodo = async (id) => {
let response = await fetch('https://jsonplaceholder.typicode.com/posts/' + id);
let r = await response.json();
return r;
}
const mainFunc = async () => {
let todo = {
title: "milan7",
body: "dai7",
userID: 101
}
let todor = await createTodo(todo);
console.log(todor);
console.log(await getTodo(5));
}
mainFunc()
I think that, we don't need parse the JSON object into a string, if the remote server accepts json into they request, just run:
const request = await fetch ('/echo/json', {
headers: {
'Content-type': 'application/json'
},
method: 'POST',
body: { a: 1, b: 2 }
});
Such as the curl request
curl -v -X POST -H 'Content-Type: application/json' -d '#data.json' '/echo/json'
In case to the remote serve not accept a json file as the body, just send a dataForm:
const data = new FormData ();
data.append ('a', 1);
data.append ('b', 2);
const request = await fetch ('/echo/form', {
headers: {
'Content-type': 'application/x-www-form-urlencoded'
},
method: 'POST',
body: data
});
Such as the curl request
curl -v -X POST -H 'Content-type: application/x-www-form-urlencoded' -d '#data.txt' '/echo/form'
You only need to check if response is ok coz the call not returning anything.
var json = {
json: JSON.stringify({
a: 1,
b: 2
}),
delay: 3
};
fetch('/echo/json/', {
method: 'post',
headers: {
'Accept': 'application/json, text/plain, */*',
'Content-Type': 'application/json'
},
body: 'json=' + encodeURIComponent(JSON.stringify(json.json)) + '&delay=' + json.delay
})
.then((response) => {if(response.ok){alert("the call works ok")}})
.catch (function (error) {
console.log('Request failed', error);
});
// extend FormData for direct use of js objects
Object.defineProperties(FormData.prototype, {
load: {
value: function (d) {
for (var v in d) {
this.append(v, typeof d[v] === 'string' ? d[v] : JSON.stringify(d[v]));
}
}
}
})
var F = new FormData;
F.load({A:1,B:2});
fetch('url_target?C=3&D=blabla', {
method: "POST",
body: F
}).then( response_handler )
you can use fill-fetch, which is an extension of fetch. Simply, you can post data as below:
import { fill } from 'fill-fetch';
const fetcher = fill();
fetcher.config.timeout = 3000;
fetcher.config.maxConcurrence = 10;
fetcher.config.baseURL = 'http://www.github.com';
const res = await fetcher.post('/', { a: 1 }, {
headers: {
'bearer': '1234'
}
});

Categories

Resources