next-crud icon indicating copy to clipboard operation
next-crud copied to clipboard

Handle invalid request

Open tlenclos opened this issue 2 years ago • 1 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"
        }
    }
}

tlenclos avatar Oct 05 '21 16:10 tlenclos

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)
    }
  }
})

jonpacker avatar Dec 27 '21 19:12 jonpacker