androidreact-nativehttpsfetch-apireact-native-debugger

urlencoded request works only if react native debugger's enable network inspect mode is switched on or in Postman


A react native app I am working on has one specific request which has a different configuration from the other requests in the app. In Postman, this request requires that I attach a token to the body using x-www-form-urlencoded. It works in Postman just fine.

This request in the react native app works when I switch on debug and enable network inspect in react native debugger. If I turn network inspect off, it fails with the error "Required request parameter 'token' for method parameter type String is not present". That is the same error if I use other formdata methods other than x-www-form-urlencoded or if I don't add the token. This is the case in ios/android emulator as well as on on physical debug device.

Why is this happening, and how can I solve it? Here is Postman screenshot, the react native request code, and the Postman-generated fetch codePostman screenshot of successful request

// POSTMAN GENERATED CODE
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/x-www-form-urlencoded");

var urlencoded = new URLSearchParams();
urlencoded.append("token", "eyblaablaablaa");

var requestOptions = {
  method: 'POST',
  headers: myHeaders,
  body: urlencoded,
  redirect: 'follow'
};

fetch("someUrl", requestOptions)
  .then(response => response.text())
  .then(result => console.log(result))
  .catch(error => console.log('error', error));




 //REACT NATIVE CODE
 export async function htmlClient2(
  redirectUrl: string,
  {
    urlEncodedBody,
    headers: customHeaders,
    ...customConfig
  }: RequestConfig = {}
): Promise<string> {
  const headers = new Headers({
    'Content-Type': 'application/x-www-form-urlencoded',
    Accept: 'text/html',
    ...customHeaders
  })

  const config: RequestInit = {
    method: 'POST',
    ...customConfig,
    headers,
    credentials: 'include',
    body: urlEncodedBody
  }

  return fetch(redirectUrl, config).then(async response => {
    const data = await response.text()
    if (response.ok) {
      return data
    } else {
      return Promise.reject(data)
    }
  })
}

Solution

  • "If you were using fetch in a browser, you could create URLSearchParams and use that as the request body. However, you can't do this in React Native because React Native does not implement URLSearchParams."

    source: Post a x-www-form-urlencoded request in React Native with fetch

    The debugger and Postman have the implementation of URLSearchParams so it works using them. In the times it worked in the debug app, it worked because I have the react-native-debugger connected and have enabled network inspect. When you enable network inspect, the debugger handles all the network requests instead of react native. That is why it worked in those scenarios but not in any other.

    So I solved it like this..

    const urlEncodableBody= {
        token: someToken
      }
    
      const config: RequestInit = {
        method: 'POST',
        ...customConfig,
        headers,
        credentials: 'include',
        body: createUrlEncodedBody(urlEncodableBody)
      }
    
    export const createUrlEncodedBody = (plainBodyObject: Object): string => {
      const encodedBody: string = Object.entries(plainBodyObject)
        .map(([key, value]) => {
          return encodeURIComponent(key) + '=' + encodeURIComponent(value)
        })
        .join('&')
      return encodedBody
    }