Home > Net >  API call to crypto.com in node returns invalid JSON response
API call to crypto.com in node returns invalid JSON response

Time:02-19

I'm sending a POST request to the crypto.com public API (reference) using node-fetch. More specifically, I'm am attempting to call the private method get-account-summary and I am signing the request beforehand with my API Key and my Secret Key as prescribed on their API reference page (see digital signature).

const requestBody = JSON.stringify(signRequest(request, apiKey, apiSecret));

fetch('https://api.crypto.com/v2/private/get-account-summary', {
  method: 'POST',
  headers: {'Content-Type': 'application/json'}, 
  body: requestBody
})
.then(response => response.body)
.then(data => {
  console.log('Success:', data);
})
.catch((error) => {
  console.error('Error:', error);
});

The request is apparently successful, but I'm struggling to make sense of the API response which is supposed to look like this:

{
    "id": 11,
    "method": "private/get-account-summary",
    "code": 0,
    "result": {
        "accounts": [
            {
                "balance": 99999999.905000000000000000,
                "available": 99999996.905000000000000000,
                "order": 3.000000000000000000,
                "stake": 0,
                "currency": "CRO"
            }
        ]
    }
}

but this is what I actually get:

Success: PassThrough {
  _readableState: ReadableState {
    objectMode: false,
    highWaterMark: 16384,
    buffer: BufferList { head: null, tail: null, length: 0 },
    length: 0,
    pipes: [],
    flowing: null,
    ended: true,
    endEmitted: false,
    reading: false,
    constructed: true,
    sync: false,
    needReadable: false,
    emittedReadable: false,
    readableListening: false,
    resumeScheduled: false,
    errorEmitted: false,
    emitClose: true,
    autoDestroy: true,
    destroyed: false,
    errored: null,
    closed: false,
    closeEmitted: false,
    defaultEncoding: 'utf8',
    awaitDrainWriters: null,
    multiAwaitDrain: false,
    readingMore: false,
    dataEmitted: false,
    decoder: null,
    encoding: null,
    [Symbol(kPaused)]: null
  },
  _events: [Object: null prototype] {
    prefinish: [Function: prefinish],
    error: [Function (anonymous)]
  },
  _eventsCount: 2,
  _maxListeners: undefined,
  _writableState: WritableState {
    objectMode: false,
    highWaterMark: 16384,
    finalCalled: true,
    needDrain: false,
    ending: true,
    ended: true,
    finished: true,
    destroyed: false,
    decodeStrings: true,
    defaultEncoding: 'utf8',
    length: 0,
    writing: false,
    corked: 0,
    sync: false,
    bufferProcessing: false,
    onwrite: [Function: bound onwrite],
    writecb: null,
    writelen: 0,
    afterWriteTickInfo: null,
    buffered: [],
    bufferedIndex: 0,
    allBuffers: true,
    allNoop: true,
    pendingcb: 0,
    constructed: true,
    prefinished: true,
    errorEmitted: false,
    emitClose: true,
    autoDestroy: true,
    errored: null,
    closed: false,
    closeEmitted: false,
    [Symbol(kOnFinished)]: []
  },
  allowHalfOpen: true,
  [Symbol(kCapture)]: false,
  [Symbol(kCallback)]: null
}

You may have noticed that I logged the response.body to the console rather than the response.json() because whenever I call the latter, I get an "invalid json error"

Error: FetchError: invalid json response body at
https://api.crypto.com/v2/private/get-account-summary reason:
Unexpected end of JSON input
    at C:\Users\...\app\node_modules\node-fetch\lib\index.js:273:32
    at processTicksAndRejections (node:internal/process/task_queues:96:5) {
  type: 'invalid-json' 

CodePudding user response:

Fetch returns a response stream. A simpler approach would be to use npm request package.

Ex :

const request = require('request');
const requestBody = JSON.stringify(signRequest(request, apiKey, apiSecret));

request('https://api.crypto.com/v2/private/get-account-summary', {
  json: true,
  method: 'POST',
  headers: {'Content-Type': 'application/json'}, 
  body: requestBody
})
.then(response => response.body)
.then(data => {
  console.log('Success:', data);
})
.catch((error) => {
  console.error('Error:', error);
});

CodePudding user response:

Many API stacks work in terms of 2 promises:

  • Make the remote request
  • Deserialize the response

According to docs you need to await the .json() call.

import fetch from 'node-fetch';

const response = await fetch('https://httpbin.org/post', {
    method: 'post',
    body: JSON.stringify(body),
    headers: {'Content-Type': 'application/json'}
});
const data = await response.json();

Nested promises looks messier when using then, which is why many people prefer the async await syntax, but this will work:

request('https://api.crypto.com/v2/private/get-account-summary', {
  json: true,
  method: 'POST',
  headers: {'Content-Type': 'application/json'}, 
  body: requestBody
})
.then(response => {
   response.json()
       .then(data => {
            console.log(data);
        })
})

CodePudding user response:

EDIT: Sorry I missed the end of the question. If json() is invalid and the text() returns nothing, I would say you should check your request body. The request is successful, but you get an empty response.

Not sure why you are using response.body. You need to use json() if you want the response in a JSON format. This will take the body and return a promise which resolve to the requested format. You can read it here.

So, your code should look like this:

fetch('https://api.crypto.com/v2/private/get-account-summary', {
  method: 'POST',
  headers: {'Content-Type': 'application/json'}, 
  body: requestBody
})
.then(response => response.json())
.then(data => {
  console.log('Success:', data);
})
.catch((error) => {
  console.error('Error:', error);
});
  • Related