premieroctet / next-crud

Full-featured CRUD routes for Next.js

Home Page:https://next-crud.js.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Handle invalid request

tlenclos opened this issue · comments

Context

From the example app, username is required.

API returns a 500 when trying to create a user without username.

image

curl 'https://qj3gn.sse.codesandbox.io/api/users' \
  -H 'authority: qj3gn.sse.codesandbox.io' \
  -H 'sec-ch-ua: "Google Chrome";v="93", " Not;A Brand";v="99", "Chromium";v="93"' \
  -H 'sec-ch-ua-mobile: ?0' \
  -H 'user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36' \
  -H 'sec-ch-ua-platform: "Linux"' \
  -H 'content-type: application/json' \
  -H 'accept: */*' \
  -H 'origin: https://qj3gn.sse.codesandbox.io' \
  -H 'sec-fetch-site: same-origin' \
  -H 'sec-fetch-mode: cors' \
  -H 'sec-fetch-dest: empty' \
  -H 'referer: https://qj3gn.sse.codesandbox.io/users/create' \
  -H 'accept-language: en-US,en;q=0.9,fr;q=0.8' \
  --data-raw '{}' \
  --compressed

Error

Invalid `prisma.user.create()` invocation:

{
  data: {
+   username: String,
?   isAdmin?: Boolean | null,
?   posts?: {
?     create?: PostCreateWithoutUserInput | PostCreateWithoutUserInput,
?     connect?: PostWhereUniqueInput | PostWhereUniqueInput,
?     connectOrCreate?: PostCreateOrConnectWithoutuserInput | PostCreateOrConnectWithoutuserInput
?   }
  },
  select: undefined,
  include: undefined
}

Argument username for data.username is missing.

Expected

API should return a 400 instead of 500, with proper error handling like

{
    errors: {
        username: {
            required: "username field is required"
        }
    }
}

I am having a similar issue, but a bigger issue here is that there is no way to allow the user to define their own error formatting.

The most obvious solution I found was to override handleError in the adapter and throw your own HttpErrors, but this is still limited to returning plain text with the HTTP status text forcibly prepended.

The best I could do was to define my own error type (for example, say: new HttpErrorWithBody(400, { error: { path: 'email', type: 'not_unique' } })), then catch that in my own onError handler and use it to return the statusCode and body on the error object. The problem with this is that onError isn't intended to be used this way, as right afterwards it proceeds to send the response body and status anyway—there's no way to disable this. One solution here would be to check res.headersSent after onError, but it just feels like a workaround to me.

There should probably be some way to define a function which is explicitly intended to format an error response. Perhaps something like this? (here I'm just replicating exactly the handling that is default today)

const handler = NextCrud({
  adapter: new PrismaAdapter({
    prismaClient: myPrismaClientInstance,
  }),
  sendErrorResponse: (req, res, error) => {
    if (e instanceof HttpError) {
      res.status(e.statusCode).send(e.message)
    } else {
      res.status(500).send(e.message)
    }
  }
})