Search code examples
javascriptnode.jsdockerstrapi

Api request status code different when using docker


I'm developing an api using strapi 3.6 that I develop without docker locally and I run with docker in production.

Locally, an endpoint that returns a 400 will become a 500 in production.

I have been investigating the issue and when I run docker locally, I also get a 500 instead of a 400.

I couldn't find any relevant resources, does someone have any clue why this could happen?

EDIT

The backend is deployed on AWS Elastic Beanstalk.

What I tried:

  • ❌ requesting the load balancer directly
  • ❌ requesting the underlying ec2 directly
  • ❌ running docker locally in production mode
  • ❌ running docker locally in dev mode
  • ✅ building strapi and running the server like docker does but without docker

All above cases gave me a 500 instead of the expected 400, except for the last case that returned a 400 as expected.

The error displayed in the logs are the ones expected. Only the way the error is returned by the api changes.

Here is the code of the middleware that handles errors globally:

module.exports = (strapi) => {
  return {
    initialize() {
      strapi.app.use(async (ctx, next) => {
        try {
          await next();
        } catch (e) {
          strapi.log.error(e, e.stack);

          // The error raised is a BusinessError
          // Logs are the ones expected
          if (e instanceof BusinessError) {
            ctx.status = 400;
            ctx.body = {
              message: e.message,
              code: e.code,
            };
          } else {
            throw e;
          }
        }
      });
    },
  };
};

EDIT 2

local logs:

[
  {
    "level": 50,
    "time": 1641722347605,
    "pid": 3986,
    "hostname": "MacBook-Pro-de-Baptiste-2.local",
    "status": 400,
    "headers": {},
    "body": {
      "code": "ValidationError",
      "message": "Validation error(s) present. See embedded errors list for more details.",
      "_embedded": {
        "errors": [{ "code": "Invalid", "message": "Invalid amount. The supplied amount is greater than your transaction limit.", "path": "/amount/value", "_links": {} }]
      }
    },
    "requestId": "eeb84a16-b250-40d2-9a53-901f92843aa1",
    "v": 1
  },
  {
    "level": 50,
    "time": 1641722347743,
    "msg": "BusinessError: User has reached their transfer limit\n    at Object.makeTransfer (/Users/baboo/Documents/projects/burrow/burrow-backend/api/dwolla/services/dwolla.js:154:13)\n    at async makeTransfer (/Users/baboo/Documents/projects/burrow/burrow-backend/api/payment/controllers/submitOrder.js:83:7)\n    at async /Users/baboo/Documents/projects/burrow/burrow-backend/api/payment/controllers/submitOrder.js:121:25",
    "pid": 3986,
    "hostname": "MacBook-Pro-de-Baptiste-2.local",
    "name": "BusinessError",
    "code": "USER_TRANSFER_LIMIT",
    "requestId": "eeb84a16-b250-40d2-9a53-901f92843aa1",
    "v": 1
  },
  {
    "level": 20,
    "time": 1641722347744,
    "msg": "POST /checkout/submit-order (7616 ms) \u001b[33m400\u001b[39m",
    "pid": 3986,
    "hostname": "MacBook-Pro-de-Baptiste-2.local",
    "requestId": "eeb84a16-b250-40d2-9a53-901f92843aa1",
    "v": 1
  }
]

Docker logs:

[
  {
    "level": 50,
    "msg": "{\"code\":\"ValidationError\",\"message\":\"Validation error(s) present. See embedded errors list for more details.\",\"_embedded\":{\"errors\":[{\"code\":\"Invalid\",\"message\":\"Invalid amount. The supplied amount is greater than your transaction limit.\",\"path\":\"/amount/value\",\"_links\":{}}]}}",
    "pid": 17,
    "hostname": "ef76780ba954",
    "type": "Error",
    "stack": "Error: {\"code\":\"ValidationError\",\"message\":\"Validation error(s) present. See embedded errors list for more details.\",\"_embedded\":{\"errors\":[{\"code\":\"Invalid\",\"message\":\"Invalid amount. The supplied amount is greater than your transaction limit.\",\"path\":\"/amount/value\",\"_links\":{}}]}}\n    at errorFrom (/strapi/node_modules/dwolla-v2/src/dwolla/Token.js:49:15)\n    at /strapi/node_modules/dwolla-v2/src/dwolla/Token.js:70:29\n    at tryCatcher (/strapi/node_modules/bluebird/js/release/util.js:16:23)\n    at Promise._settlePromiseFromHandler (/strapi/node_modules/bluebird/js/release/promise.js:547:31)\n    at Promise._settlePromise (/strapi/node_modules/bluebird/js/release/promise.js:604:18)\n    at Promise._settlePromise0 (/strapi/node_modules/bluebird/js/release/promise.js:649:10)\n    at Promise._settlePromises (/strapi/node_modules/bluebird/js/release/promise.js:729:18)\n    at _drainQueueStep (/strapi/node_modules/bluebird/js/release/async.js:93:12)\n    at _drainQueue (/strapi/node_modules/bluebird/js/release/async.js:86:9)\n    at Async._drainQueues (/strapi/node_modules/bluebird/js/release/async.js:102:5)\n    at Immediate.Async.drainQueues [as _onImmediate] (/strapi/node_modules/bluebird/js/release/async.js:15:14)\n    at processImmediate (internal/timers.js:464:21)",
    "status": 400,
    "headers": {},
    "body": {
      "code": "ValidationError",
      "message": "Validation error(s) present. See embedded errors list for more details.",
      "_embedded": {
        "errors": [{ "code": "Invalid", "message": "Invalid amount. The supplied amount is greater than your transaction limit.", "path": "/amount/value", "_links": {} }]
      }
    },
    "v": 1
  },
  {
    "level": 50,
    "msg": "User has reached their transfer limit",
    "pid": 17,
    "hostname": "ef76780ba954",
    "type": "Error",
    "stack": "BusinessError: User has reached their transfer limit\n    at Object.makeTransfer (/strapi/api/dwolla/services/dwolla.js:154:13)\n    at async makeTransfer (/strapi/api/payment/controllers/submitOrder.js:83:7)\n    at async /strapi/api/payment/controllers/submitOrder.js:121:25",
    "name": "BusinessError",
    "code": "USER_TRANSFER_LIMIT",
    "isBoom": true,
    "isServer": true,
    "data": null,
    "output": { "statusCode": 500, "payload": { "statusCode": 500, "error": "Internal Server Error", "message": "An internal server error occurred" }, "headers": {} },
    "v": 1
  },
  {
    "level": 20,
    "msg": "POST /checkout/submit-order (3390 ms) 500",
    "pid": 17,
    "hostname": "ef76780ba954",
    "v": 1
  }
]

Solution

  • Looking at the logs, I saw that in production I had this line returned by the api:

    ...
    "isBoom": true,
    ...
    

    This means that the error is handled by the global error handler boom that comes with strapi by default.

    But we created our own global error handler.

    Having a deeper look at the logs, I also saw that the property requestId was missing in production, a piece of information we also add in one of our custom middleware.

    I deduced that our middlewares were not loaded in production.

    And when opening the Dockerfile, I had the answer to our troubles: we are simply not copying the middlewares folder when building the image.

    It's all good now.

    Thanks @OneCricketeer to have pointed me in the right direction 🤜🤛