j-p
j-p

Reputation: 3828

NodeJS passing POST to external API using POST

Getting a dreaded JSON error .

I am using an external API that allegedly takes a POST to add a user to a group. in my nodeJS express app - I want to pass-thru the data coming from my app to the external API.

my "GET" methods work - but now I am trying to take a form submitted to my app, and pass the data to an external API using "POST".

Here is the code I am testing (assume the api url and credentials are correct - and NOT the issue) I have tested the external API passing the same JSON object directly to the external API using Postman, and it works without error.

const express = require('express');
const router = express.Router();
const https = require('https');


    function callExternalAPI( RequestOptions ) {
        return new Promise((resolve, reject) => {
            https.request(
                RequestOptions,
                function(response) {
                    const { statusCode } = response;
                    if (statusCode >= 300) {
                        reject(
                            new Error( response.statusMessage )
                        );
                    }

                    const chunks = [];

                    response.on('data', (chunk) => {
                        chunks.push(chunk);
                    });

                    response.on('end', () => {
                        const result = Buffer.concat(chunks).toString();
                        resolve( JSON.parse(result) );
                    });

                }
            )
            .end();
        })
    }


    router.get('/thing', /*auth,*/ ( req, res, next ) => {

        callExternalAPI(
            {
                host: 'api_url',
                path: '/list',
                method: 'GET',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': 'Basic ' + new Buffer( auth_un + ':' + auth_pw ).toString('base64')
                }
            }
        )
        .then(
            response => {
                console.log(response);
            }
        )
        .catch(
            error => {
                console.log(error);             
            }
        );

    });


    router.post('/thing', /*auth,*/ ( req, res, next ) => {

        callExternalAPI(
            {
                host: 'api_url',
                path: '/addThing',
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': 'Basic ' + new Buffer( auth_un + ':' + auth_pw ).toString('base64')
                },
                data: {
                    'group_id': req.body.group_id,
                    'person_id': req.body.person_id
                }
            }
        )
        .then(
            response => {
                console.log(response);
            }
        )
        .catch(
            error => {
                console.log(error);             
            }
        );

    });

module.exports = router;

console logging the req.body looks lie this

{ group_id: '45b62b61-62fa-4684-a058-db3ef284f699',  person_id: '3b1c915c-3906-42cf-8084-f9a25179d6b2' }

And the error looks like this

undefined:1
<html><title>JSpring Application Exception</title>
<h2>JSpring Exception Stack Trace</h2>
<pre>SafeException: FiberServer.parsers.parseJSONBuf(): JSON parse failed.
^    
SyntaxError: Unexpected token < in JSON at position 0

Granted the console.log of the req.body does not have the required double quotes, but I think that is just the log dump format - but it might be munging the JSON. I have tried wrapping this in stringify; meaning something like this: data: JSON.stringify( req.body ) (but the same error occurs).

callExternalAPI(
            {
                host: 'api_url',
                path: '/addThing',
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': 'Basic ' + new Buffer( auth_un + ':' + auth_pw ).toString('base64')
                },
                **data: JSON.stringify( req.body )**
            }
        )

I am testing this in postman, having the body be 'raw json' with headers as 'application/json' the body is this:

{
    "group_id": "45b62b61-62fa-4684-a058-db3ef284f699", 
    "person_id": "3b1c915c-3906-42cf-8084-f9a25179d6b2"
}

Upvotes: 1

Views: 1222

Answers (2)

antonku
antonku

Reputation: 7685

You should try to write the POST payload in the request body instead of passing it inside the options object:

function callExternalAPI( RequestOptions ) {
  const { data, ...options } = RequestOptions;
  return new Promise((resolve, reject) => {
    const req = https.request(
      options,
      function(response) {
        const { statusCode } = response;
        if (statusCode >= 300) {
          reject(
            new Error( response.statusMessage )
          );
        }

        const chunks = [];

        response.on('data', (chunk) => {
          chunks.push(chunk);
        });

        response.on('end', () => {
          const result = Buffer.concat(chunks).toString();
          resolve( JSON.parse(result) );
        });

      }
    );
    req.write(JSON.stringify(data));
    req.end();
  })
}

Upvotes: 1

har17bar
har17bar

Reputation: 884

In express you must use bodyParser At the top of the file when you initializing your express app add this lines

const app = express()
const bodyParser = require('body-parser')
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())

https://medium.com/@adamzerner/how-bodyparser-works-247897a93b90

Upvotes: 0

Related Questions