Unable to get request body in middleware

System Information
  • Strapi Version: 3.2.5
  • Operating System: Ubuntu 20.04
  • Database: PostgreSQL
  • Node Version: 14.13.0
  • NPM Version: -
  • Yarn Version: -

I have managed to make middleware work in Strapi. But, I can’t see the body in the request.

Inside /middlewares/getEmail/index.js, I Have

module.exports = (strapi) => {
      return {
        initialize: function (cb) {
          strapi.app.use(async (ctx, next) => {
            if (ctx.method === "POST" && ctx.url === "/email-leads") {
              console.log(ctx);
            }
            await next();
          });
        },
      };
};

and ctx request logs:

  request: {
    method: 'POST',
    url: '/email-leads',
    header: {
      'content-type': 'application/json',
      accept: 'application/json',
      'user-agent': 'PostmanRuntime/7.26.8',
      'postman-token': 'xxx',
      host: 'localhost:1337',
      'accept-encoding': 'gzip, deflate, br',
      connection: 'keep-alive',
      'content-length': '33'
    }
  },

This is the only middleware I have written on this application. In the /config/middleware.js, I have

module.exports = {
  load: {
    before: ["getEmail", "responseTime", "logger", "cors", "responses", "gzip"],
    order: ["parser"],
    after: ["router"],
  },
  settings: {
    getEmail: {
      enabled: true,
    },
  },
};

I read about this koa-body/unparsed.js to read the body but there’s literally no body in the ctx.request. Thanks for help.

1 Like

Well, in this case, you should put your middleware at the end of all core middleware, after body parser.

after: ["parser","router","getEmail"],

Also, from your code is clear that you should not use middlewares in this case, because you use them only for a single route:

if (ctx.method === "POST" && ctx.url === "/email-leads") {
              console.log(ctx);
            }

You should use policies, and it must be used only for POST /email-leads route, take a look at the attached link to find the policies documentation.

1 Like

It’s due to when the middleware is loaded, can you try moving it into the after array?

1 Like

Hi, thanks for taking time. I have changed it to this

module.exports = {
  load: {
    before: ["responseTime", "logger", "cors", "responses", "gzip"],
    after: ["parser", "router", "getEmail"],
  },
  settings: {
    getEmail: {
      enabled: true,
    },
  },
};

Still didn’t have body in request.

request: {
    method: 'POST',
    url: '/email-leads',
    header: {
      'content-type': 'application/json',
      accept: 'application/json',
      'user-agent': 'PostmanRuntime/7.26.8',
      'postman-token': 'b1886cff-70e1-4ed5-87fd-3125f8d6adf0',
      host: 'localhost:1337',
      'accept-encoding': 'gzip, deflate, br',
      connection: 'keep-alive',
      'content-length': '32'
    }
  },

Then, I have used the policy as suggested.

module.exports = async (ctx, next) => {
  console.log(ctx, "policy");
  return await next();
};

But unfortunately, I still get the same request. As I see, the content-length is 32. which is exactly the body I send if /n is included.

{
“email”: “test@test.com
}

I am copying the whole ctx log in case it might be showing something that I can’t see.

{
  request: {
    method: 'POST',
    url: '/email-leads',
    header: {
      'content-type': 'application/json',
      accept: 'application/json',
      'user-agent': 'PostmanRuntime/7.26.8',
      'postman-token': 'xxxxxxxxxxxxxxxxxxxxxxxxxxx',
      host: 'localhost:1337',
      'accept-encoding': 'gzip, deflate, br',
      connection: 'keep-alive',
      'content-length': '32'
    }
  },
  response: {
    status: 404,
    message: 'Not Found',
    header: [Object: null prototype] {
      vary: 'Origin',
      'strict-transport-security': 'max-age=31536000; includeSubDomains',
      'x-frame-options': 'SAMEORIGIN'
    }
  },
  app: { subdomainOffset: 2, proxy: false, env: 'development' },
  originalUrl: '/email-leads',
  req: '<original node req>',
  res: '<original node res>',
  socket: '<original node socket>'
}

Thanks for the suggestion. I have put it in the after array. In all possible indices, it just gave the same request

Can you try console.log(ctx.request.body)

The object is not present when outputting the ctx, but it is there.

1 Like

Yes, worked. Shocked, actually. I’ll just use the Policy. But, is there documentation to understand how these middlewares should be put in before - order - after?

Interesting it is there and not shown in console.log. Thanks for your answer.

Overall, to read the request body in the middleware, I have tried to put getEmail in after array and I can reach the request body if I place the middleware after parser middleware or to the end as @sunnyson suggests.

1 Like

Try:

module.exports = async (ctx, next) => {
  await next();
  console.log(ctx, "policy");
};

Also @sunnyson is also correct, the ctx is a prototype so the values aren’t logged unless you specify them.

Actually, it worked as above @DMehaffy, but yes it must be the reason why ctx.body is not logged. Thanks.

Middlewares are loaded twice during the request chain:

BEFORE => Any code before the await next()
AFTER => Any code after the await next()

This also applies to route policies, I won’t break down the full Koa request chain but the gist goes something like:

  • User makes request
  • Koa “stuff”
  • Koa middlewares (before)
  • Users permissions plugin
  • Check policies (before)
  • Controller (handler)
  • Service
  • DB Stuff
  • Reverse Chain
  • policies (after)
  • middleware (after)
  • Koa stuff
  • User gets response
1 Like