1

I want to hit an API inside my cloud functions so I'm using axios to make my http multipart/form-data post request.

When I by-pass my cloud functions and put my endpoint API directly inside Postman, everything works as expected. But when I put the function endpoint in Postman, it fails. I also took a look at the node-js axios code builder in Postman and my code should be correct. I read all others related posts but unable to solve my issue.

I also read this document from Google https://cloud.google.com/blog/topics/developers-practitioners/avoiding-gcf-anti-patterns-part-4-how-handle-promises-correctly-your-nodejs-cloud-function and I noticed that I have almost the same request, at the only difference that mine fails.

I thought that it was axios but replacing it by node-fetch didn't change anything.

Any help would be appreciated.

Here is my function :

exports.submit = functions.https.onRequest(async (req, res) => {
try {
    const form = new FormData();
    form.append('holder', '{firstName:XXX, birthName:XXXX, birthDate:XXXX-XX-XX}');
    const response = await axios({
        method: 'post',
        url: 'https://integration.xxx.io/v2',
        data: form,
        headers: {
            'accept': 'application/json',
            'Content-Type': 'multipart/form-data',
            'Authorization': 'Basic XXX=',
        },
    });
    console.log(response);
    res.status(200).send({
        success: true,
        data: response.data
    });
} catch (error) {
    console.log(error);
    res.status(400).send({
        success: false,
        error: error,
    });
}
});

The error printed on Postman :

{
"success": false,
"error": {
    "message": "socket hang up",
    "name": "Error",
    "stack": "Error: socket hang up\n    at connResetException (node:internal/errors:691:14)\n    at TLSSocket.socketOnEnd (node:_http_client:471:23)\n    at TLSSocket.emit (node:events:402:35)\n    at TLSSocket.emit (node:domain:537:15)\n    at endReadableNT (node:internal/streams/readable:1343:12)\n    at processTicksAndRejections (node:internal/process/task_queues:83:21)",
    "config": {
        "transitional": {
            "silentJSONParsing": true,
            "forcedJSONParsing": true,
            "clarifyTimeoutError": false
        },
        "transformRequest": [
            null
        ],
        "transformResponse": [
            null
        ],
        "timeout": 0,
        "xsrfCookieName": "XSRF-TOKEN",
        "xsrfHeaderName": "X-XSRF-TOKEN",
        "maxContentLength": -1,
        "maxBodyLength": -1,
        "headers": {
            "Accept": "application/json",
            "Content-Type": "multipart/form-data",
            "Authorization": "Basic XXX=",
            "User-Agent": "axios/0.26.1"
        },
        "method": "post",
        "url": "https://integration.xxx.io/v2",
        "data": {
            "_overheadLength": 211,
            "_valueLength": 120,
            "_valuesToMeasure": [],
            "writable": false,
            "readable": true,
            "dataSize": 0,
            "maxDataSize": 2097152,
            "pauseStreams": true,
            "_released": true,
            "_streams": [],
            "_currentStream": null,
            "_insideLoop": false,
            "_pendingNext": false,
            "_boundary": "--------------------------045202360965403790737146",
            "_events": {},
            "_eventsCount": 1
        }
    },
    "code": "ECONNRESET",
    "status": null
},

EDIT: Adding Cloud functions logs

submit
Error: socket hang up
at connResetException(node: internal / errors: 691: 14)
at TLSSocket.socketOnEnd(node: _http_client: 471: 23)
at TLSSocket.emit(node: events: 402: 35)
at TLSSocket.emit(node: domain: 537: 15)
at endReadableNT(node: internal / streams / readable: 1343: 12)
at processTicksAndRejections(node: internal / process / task_queues: 83: 21) {
    code: 'ECONNRESET',
    config: {
        transitional: {
            silentJSONParsing: true,
            forcedJSONParsing: true,
            clarifyTimeoutError: false
        },
        adapter: [Function: httpAdapter],
        transformRequest: [
            [Function: transformRequest]
        ],
        transformResponse: [
            [Function: transformResponse]
        ],
        timeout: 0,
        xsrfCookieName: 'XSRF-TOKEN',
        xsrfHeaderName: 'X-XSRF-TOKEN',
        maxContentLength: -1,
        maxBodyLength: -1,
        validateStatus: [Function: validateStatus],
        headers: {
            Accept: 'application/json',
            'Content-Type': 'multipart/form-data',
            Authorization: 'Basic XXX=',
            'User-Agent': 'axios/0.26.1'
        },
        method: 'post',
        url: 'https://integration.xxx.io/v2',
        data: FormData {
            _overheadLength: 211,
            _valueLength: 120,
            _valuesToMeasure: [],
            writable: false,
            readable: true,
            dataSize: 0,
            maxDataSize: 2097152,
            pauseStreams: true,
            _released: true,
            _streams: [],
            _currentStream: null,
            _insideLoop: false,
            _pendingNext: false,
            _boundary: '--------------------------196369661580838061893871',
            _events: [Object: null prototype],
            _eventsCount: 1
        }
    },
    request: < ref * 1 > Writable {
        _writableState: WritableState {
            objectMode: false,
            highWaterMark: 16384,
            finalCalled: false,
            needDrain: false,
            ending: false,
            ended: false,
            finished: false,
            destroyed: false,
            decodeStrings: true,
            defaultEncoding: 'utf8',
            length: 0,
            writing: false,
            corked: 0,
            sync: true,
            bufferProcessing: false,
            onwrite: [Function: bound onwrite],
            writecb: null,
            writelen: 0,
            afterWriteTickInfo: null,
            buffered: [],
            bufferedIndex: 0,
            allBuffers: true,
            allNoop: true,
            pendingcb: 0,
            constructed: true,
            prefinished: false,
            errorEmitted: false,
            emitClose: true,
            autoDestroy: true,
            errored: null,
            closed: false,
            closeEmitted: false,
            [Symbol(kOnFinished)]: []
        },
        _events: [Object: null prototype] {
            response: [Function: handleResponse],
            error: [Function: handleRequestError],
            socket: [Function: handleRequestSocket]
        },
        _eventsCount: 3,
        _maxListeners: undefined,
        _options: {
            maxRedirects: 21,
            maxBodyLength: 10485760,
            protocol: 'https:',
            path: '/v2',
            method: 'POST',
            headers: [Object],
            agent: undefined,
            agents: [Object],
            auth: undefined,
            hostname: 'integration.xxx.io',
            port: null,
            nativeProtocols: [Object],
            pathname: '/v2'
        },
        _ended: true,
        _ending: true,
        _redirectCount: 0,
        _redirects: [],
        _requestBodyLength: 387,
        _requestBodyBuffers: [
            [Object],
            [Object],
            [Object],
            [Object],
            [Object],
            [Object]
        ],
        _onNativeResponse: [Function(anonymous)],
        _currentRequest: ClientRequest {
            _events: [Object: null prototype],
            _eventsCount: 7,
            _maxListeners: undefined,
            outputData: [],
            outputSize: 0,
            writable: true,
            destroyed: false,
            _last: true,
            chunkedEncoding: true,
            shouldKeepAlive: false,
            maxRequestsOnConnectionReached: false,
            _defaultKeepAlive: true,
            useChunkedEncodingByDefault: true,
            sendDate: false,
            _removedConnection: false,
            _removedContLen: false,
            _removedTE: false,
            _contentLength: null,
            _hasBody: true,
            _trailer: '',
            finished: true,
            _headerSent: true,
            _closed: false,
            socket: [TLSSocket],
            _header: 'POST /v2 HTTP/1.1\r\n' +
                'Accept: application/json\r\n' +
                'Content-Type: multipart/form-data\r\n' +
                'Authorization: Basic XXX=\r\n' +
                'User-Agent: axios/0.26.1\r\n' +
                'Host: integration.xxx.io\r\n' +
                'Connection: close\r\n' +
                'Transfer-Encoding: chunked\r\n' +
                '\r\n',
            _keepAliveTimeout: 0,
            _onPendingData: [Function: nop],
            agent: [Agent],
            socketPath: undefined,
            method: 'POST',
            maxHeaderSize: undefined,
            insecureHTTPParser: undefined,
            path: '/v2',
            _ended: false,
            res: null,
            aborted: false,
            timeoutCb: null,
            upgradeOrConnect: false,
            parser: null,
            maxHeadersCount: null,
            reusedSocket: false,
            host: 'integration.xxx.io',
            protocol: 'https:',
            _redirectable: [Circular * 1],
            [Symbol(kCapture)]: false,
            [Symbol(kNeedDrain)]: false,
            [Symbol(corked)]: 0,
            [Symbol(kOutHeaders)]: [Object: null prototype]
        },
        _currentUrl: 'https://integration.xxx.io/v2',
        [Symbol(kCapture)]: false
    },
    response: undefined,
    isAxiosError: true,
    toJSON: [Function: toJSON]
}
Function execution took 1127 ms. Finished with status: response error 
JM Gelilio
  • 3,482
  • 1
  • 11
  • 23
redbnlrg
  • 267
  • 1
  • 9

2 Answers2

1

Ok, so after one whole day lost looking for the solution, for others facing the same issue, this is my workaround :

As my logs pointed out showing an axios error isAxiosError: true, I decided to replace axios by unirest npm package. There is couple of HTTP librairies in npm using approximatively the same methodology (take a look to this answer : https://stackoverflow.com/a/55841420/13775978).

So, I still don't know where I'm wrong using the axios package, but works as expected using unirest package. It doesn't look like a cloud function error.

I accept this answer until a real solution is suggested.

Here is my functional function using unirest:

exports.submit = functions.https.onRequest(async (req, res) => {
    try {
        const response = await unirest
            .post('https://integration.xxx.io/v2')
            .headers({
                'accept': 'application/json',
                'Content-Type': 'multipart/form-data',
                'Authorization': 'Basic XXX=',
            })
            .field('holder', '{firstName:XXX, birthName:XXX, birthDate:XXX}');

        functions.logger.log(response);
        res.status(200).send({
            success: true,
            response: response.body,
        });
    } catch (error) {
        functions.logger.log(error);
        res.status(400).send({
            success: false,
            error: error,
        });
    }
});
redbnlrg
  • 267
  • 1
  • 9
0

Faced with same behaviour. In my case problew was with my lambda function. I declared variables like API_LINK, REQ_FORM_DATA and etc. outside exports.handler. So, first time on lambda init i got success response with correct data, and then all next requests failed with socket hang up because alive lambda did not see variables declared out of exports.handler function body.

MadaShindeInai
  • 432
  • 4
  • 16