texas697
texas697

Reputation: 6417

How do I POST a x-www-form-urlencoded request using Fetch?

I have some parameters that I want to POST form-encoded to my server:

{
    'userName': '[email protected]',
    'password': 'Password!',
    'grant_type': 'password'
}

I'm sending my request (currently without parameters) like this

var obj = {
  method: 'POST',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
  },
};
fetch('https://example.com/login', obj)
  .then(function(res) {
    // Do stuff with result
  }); 

How can I include the form-encoded parameters in the request?

Upvotes: 417

Views: 420928

Answers (19)

Nikita Koksharov
Nikita Koksharov

Reputation: 10813

Here is the code I used to convert FormData into "application/x-www-form-urlencoded" type

const formData = new FormData(form);
const urlSearchParams = new URLSearchParams();

formData.forEach((value, key) => {
  urlSearchParams.append(key, value);
});

fetch('/form', {
    method: 'POST',
    body: urlSearchParams,
})

Upvotes: 0

Marco Antonio Godoy
Marco Antonio Godoy

Reputation: 1

Posting this in case it helps anyone:

I've been working on the integration with an OAuth2.0 server provided by one of our partners. The vendor's API documentation asks to provide the "Content-Type: application/x-www-form-urlencoded" header on each request. However, while attempting to send a POST request to get the access token, the server kept responding with an HTTP 400 "Invalid request" error. After several tries, I realized that the vendor's OAUTh server seems to be expecting the value of the "redirect_uri" to be unencoded. Therefore, as a workaround, I had to manually encode each value of the payload and leave the "redirect_uri" unencoded.

Here's an example of the code for your reference:

const getAccessToken = () => {
    let payloadEncoded = '';
    payloadEncoded += 'client_id=' + <OAUTH CLIENT ID>
    payloadEncoded += '&client_secret=' + <OAUTH SECRET>
    payloadEncoded += '&grant_type=authorization_code';
    payloadEncoded += '&code=' + <OAUTH CODE>
    payloadEncoded += '&redirect_uri=https://<REDIRECT URI UNENCODED>';

    const options = {
        method: 'POST',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
        },
        body: payloadEncoded
    };

    fetch('https://<OAUTH SERVER HOST>/c2id/token', options)
        .then(response => response.json())
        .then(data => {console.log(data);
        .catch(error => console.error(error));
}

Obviously, I will reach out to the vendor to make the correction on their side.

I hope this helps!

Upvotes: -1

user16422658
user16422658

Reputation:

You can use UrlSearchParams and then do a toString() like so:

Here is a simple way of doing it:

fetch('https://example.com/login', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
    },
    body: new URLSearchParams({
        'userName': '[email protected]',
        'password': 'Password!',
        'grant_type': 'password'
    })
    .toString()
})
.then(res => {
    //Deal with response:
})

Upvotes: 26

P-A
P-A

Reputation: 1278

Just did this and UrlSearchParams did the trick Here is my code if it helps someone

import 'url-search-params-polyfill';
const userLogsInOptions = (username, password) => {



// const formData = new FormData();
  const formData = new URLSearchParams();
  formData.append('grant_type', 'password');
  formData.append('client_id', 'XXXX-app');
  formData.append('username', username);
  formData.append('password', password);
  return (
    {
      method: 'POST',
      headers: {
        // "Content-Type": "application/json; charset=utf-8",
        "Content-Type": "application/x-www-form-urlencoded",
    },
      body: formData.toString(),
    json: true,
  }
  );
};


const getUserUnlockToken = async (username, password) => {
  const userLoginUri = `${scheme}://${host}/auth/realms/${realm}/protocol/openid-connect/token`;
  const response = await fetch(
    userLoginUri,
    userLogsInOptions(username, password),
  );
  const responseJson = await response.json();
  console.log('acces_token ', responseJson.access_token);
  if (responseJson.error) {
    console.error('error ', responseJson.error);
  }
  console.log('json ', responseJson);
  return responseJson.access_token;
};

Upvotes: 40

alex_1948511
alex_1948511

Reputation: 7369

Even simpler:

fetch('https://example.com/login', {
    method: 'POST',
    headers:{
      'Content-Type': 'application/x-www-form-urlencoded'
    },    
    body: new URLSearchParams({
        'userName': '[email protected]',
        'password': 'Password!',
        'grant_type': 'password'
    })
});

Docs: https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch

Upvotes: 546

ikhvjs
ikhvjs

Reputation: 5977

You can use FormData and URLSearchParams to post as application/x-www-form-urlencoded with the example below:

If you have a form:

<form>
    <input name="username" type="text" />
    <input name="password" type="password" />
    <button type="submit">login</button>
</form>

You can add use the JS below to submit the form.

const form = document.querySelector("form");

form.addEventListener("submit", async () => {
    const formData = new FormData(form);
    try {
        await fetch("https://example.com/login", {
            method: "POST",
            headers: {
                "Content-Type": "application/x-www-form-urlencoded",
            },
            body: new URLSearchParams(formData),
        });
    } catch (err) {
        console.log(err);
    }
});

Upvotes: 11

Neurotransmitter
Neurotransmitter

Reputation: 6827

No need to use jQuery, querystring or manually assemble the payload. URLSearchParams is a way to go and here is one of the most concise answers with the full request example:

fetch('https://example.com/login', {
  method: 'POST',
  body: new URLSearchParams({
    param: 'Some value',
    anotherParam: 'Another value'
  })
})
  .then(response => {
    // Do stuff with the response
  });

The same technique using async / await.

const login = async () => {
  const response = await fetch('https://example.com/login', {
    method: 'POST',
    body: new URLSearchParams({
      param: 'Some value',
      anotherParam: 'Another value'
    })
  })

  // Do stuff with the response
}

Yes, you can use Axios or any other HTTP client library instead of native fetch.

Upvotes: 23

Ali80
Ali80

Reputation: 8696

wrapped fetch in a simple function

async function post_www_url_encdoded(url, data) {
    const body = new URLSearchParams();
    for (let key in data) {
        body.append(key, data[key]);
    }
    return await fetch(url, { method: "POST", body });
}

const response = await post_www_url_encdoded("https://example.com/login", {
    "name":"ali",
    "password": "1234"});
if (response.ok){ console.log("posted!"); }

Upvotes: 1

Hazem AbdelHamid
Hazem AbdelHamid

Reputation: 259

Just set the body as the following

var reqBody = "username="+username+"&password="+password+"&grant_type=password";

then

fetch('url', {
      method: 'POST',
      headers: {
          //'Authorization': 'Bearer token',
          'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
      },
      body: reqBody
  }).then((response) => response.json())
      .then((responseData) => {
          console.log(JSON.stringify(responseData));
      }).catch(err=>{console.log(err)})

Upvotes: 3

rufeng
rufeng

Reputation: 121

You can use react-native-easy-app that is easier to send http request and formulate interception request.

import { XHttp } from 'react-native-easy-app';

* Synchronous request
const params = {name:'rufeng',age:20}
const response = await XHttp().url(url).param(params).formEncoded().execute('GET');
const {success, json, message, status} = response;


* Asynchronous requests
XHttp().url(url).param(params).formEncoded().get((success, json, message, status)=>{
    if (success){
       this.setState({content: JSON.stringify(json)});
    } else {
       showToast(msg);
    }
});

Upvotes: 2

mahsa k
mahsa k

Reputation: 655

var details = {
    'userName': '[email protected]',
    'password': 'Password!',
    'grant_type': 'password'
};

var formBody = [];
for (var property in details) {
  var encodedKey = encodeURIComponent(property);
  var encodedValue = encodeURIComponent(details[property]);
  formBody.push(encodedKey + "=" + encodedValue);
}
formBody = formBody.join("&");

fetch('http://identity.azurewebsites.net' + '/token', {
  method: 'POST',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/x-www-form-urlencoded'
  },
  body: formBody
})

it is so helpful for me and works without any error

refrence : https://gist.github.com/milon87/f391e54e64e32e1626235d4dc4d16dc8

Upvotes: 11

Akshita Agarwal
Akshita Agarwal

Reputation: 255

*/ import this statement */
import qs from 'querystring'

fetch("*your url*", {
            method: 'POST',
            headers: {'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'},
            body: qs.stringify({ 
                username: "akshita",
                password: "123456",
            })
    }).then((response) => response.json())
      .then((responseData) => {
         alert(JSON.stringify(responseData))
    })

After using npm i querystring --save it's work fine.

Upvotes: 8

papiro
papiro

Reputation: 2365

According to the spec, using encodeURIComponent won't give you a conforming query string. It states:

  1. Control names and values are escaped. Space characters are replaced by +, and then reserved characters are escaped as described in [RFC1738], section 2.2: Non-alphanumeric characters are replaced by %HH, a percent sign and two hexadecimal digits representing the ASCII code of the character. Line breaks are represented as "CR LF" pairs (i.e., %0D%0A).
  2. The control names/values are listed in the order they appear in the document. The name is separated from the value by = and name/value pairs are separated from each other by &.

The problem is, encodeURIComponent encodes spaces to be %20, not +.

The form-body should be coded using a variation of the encodeURIComponent methods shown in the other answers.

const formUrlEncode = str => {
  return str.replace(/[^\d\w]/g, char => {
    return char === " " 
      ? "+" 
      : encodeURIComponent(char);
  })
}

const data = {foo: "bar߃©˙∑  baz", boom: "pow"};

const dataPairs = Object.keys(data).map( key => {
  const val = data[key];
  return (formUrlEncode(key) + "=" + formUrlEncode(val));
}).join("&");

// dataPairs is "foo=bar%C3%9F%C6%92%C2%A9%CB%99%E2%88%91++baz&boom=pow"

Upvotes: 3

wishy
wishy

Reputation: 1948

If you are using JQuery, this works too..

fetch(url, {
      method: 'POST', 
      body: $.param(data),
      headers:{
        'Content-Type': 'application/x-www-form-urlencoded'
      }
})

Upvotes: 4

Mojtaba Shayegh
Mojtaba Shayegh

Reputation: 391

Just Use

import  qs from "qs";
 let data = {
        'profileId': this.props.screenProps[0],
        'accountId': this.props.screenProps[1],
        'accessToken': this.props.screenProps[2],
        'itemId': this.itemId
    };
    return axios.post(METHOD_WALL_GET, qs.stringify(data))

Upvotes: 4

Narongdej Sarnsuwan
Narongdej Sarnsuwan

Reputation: 5537

You have to put together the x-www-form-urlencoded payload yourself, like this:

var details = {
    'userName': '[email protected]',
    'password': 'Password!',
    'grant_type': 'password'
};

var formBody = [];
for (var property in details) {
  var encodedKey = encodeURIComponent(property);
  var encodedValue = encodeURIComponent(details[property]);
  formBody.push(encodedKey + "=" + encodedValue);
}
formBody = formBody.join("&");

fetch('https://example.com/login', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
  },
  body: formBody
})

Note that if you were using fetch in a (sufficiently modern) browser, instead of React Native, you could instead create a URLSearchParams object and use that as the body, since the Fetch Standard states that if the body is a URLSearchParams object then it should be serialised as application/x-www-form-urlencoded. However, you can't do this in React Native because React Native does not implement URLSearchParams.

Upvotes: 515

Nicu Criste
Nicu Criste

Reputation: 3288

Use URLSearchParams

https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams

var data = new URLSearchParams();
data.append('userName', '[email protected]');
data.append('password', 'Password');
data.append('grant_type', 'password');

Upvotes: 85

David Kay
David Kay

Reputation: 1000

For uploading Form-Encoded POST requests, I recommend using the FormData object.

Example code:

var params = {
    userName: '[email protected]',
    password: 'Password!',
    grant_type: 'password'
};

var formData = new FormData();

for (var k in params) {
    formData.append(k, params[k]);
}

var request = {
    method: 'POST',
    headers: headers,
    body: formData
};

fetch(url, request);

Upvotes: -72

Quentin
Quentin

Reputation: 944498

In the original example you have a transformRequest function which converts an object to Form Encoded data.

In the revised example you have replaced that with JSON.stringify which converts an object to JSON.

In both cases you have 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' so you are claiming to be sending Form Encoded data in both cases.

Use your Form Encoding function instead of JSON.stringify.


Re update:

In your first fetch example, you set the body to be the JSON value.

Now you have created a Form Encoded version, but instead of setting the body to be that value, you have created a new object and set the Form Encoded data as a property of that object.

Don't create that extra object. Just assign your value to body.

Upvotes: 1

Related Questions