IdoPesok / zsa

https://zsa.vercel.app
MIT License
436 stars 13 forks source link

Experimental shapeError and OpenAPI #111

Closed blechatellier closed 3 weeks ago

blechatellier commented 3 weeks ago

Hey,

Thanks for implementing the experimental global shapeError method, this is exactly what I needed. What's the best way to customise the OpenAPI error code (returns 500 by default). Should you use status if the property is in the error returned by shapeError?

{
    "type": "NotFound",
    "status": 404,
    "message": "Organization not found"
}

This way you could remove shapeError from the router possibly.

IdoPesok commented 3 weeks ago

Hi, happy to hear it is useful! You should be able to return these codes and that will determine the OpenAPI status.

So for example, if the error contains { code: "PAYLOAD_TOO_LARGE" }, the request will have a 413 status code. However, I am happy to also add ability to just use status as well instead of code if that is what you are looking for.

IdoPesok commented 3 weeks ago

For reference, this is the code that handles it: https://github.com/IdoPesok/zsa/blob/main/packages/zsa-openapi/src/utils.ts#L28

blechatellier commented 3 weeks ago

Thanks, I should be able to use the built-in errors codes, what if we want to extend them? It forces to use your implementation of error code (which is probably fine but not 100% generic).

IdoPesok commented 3 weeks ago

Good point, to mitigate this for now, I just made a release zsa-openapi@0.0.12 where you can return your own responses in shape errors. So for example, something like this would work:

  .experimental_shapeError(({ err }) => {
    return new Response(JSON.stringify({ myCustomError: true }), {
      status: 123,
    })
  })

This puts you fully in the control seat of the returned error response.

blechatellier commented 3 weeks ago

@IdoPesok awesome 🙏

blechatellier commented 3 weeks ago

@IdoPesok I must be doing something wrong but keep getting a 500 and nothing in the logs.

export const { GET, POST, DELETE, PATCH } = createRouteHandlers(router, {
  shapeError: (error: unknown) => {
    return new Response(JSON.stringify(error), {
      status: error.status,
    });
  },
});
IdoPesok commented 3 weeks ago

Ah I only added it for the shape errors on actions/procedures (experimental_shapeError). I can add it to the router one as well if it's needed.

IdoPesok commented 3 weeks ago

Hi, I just made another release that will allow Responses in the router's shapeError function. Under zsa-openapi@0.1.1. Do be aware this does introduce a breaking change. For requests that accept a body (POST and PUT), you must manually define the accepted content types - if they are not application/json. So if you had any requests that accepted form data, you must now define this manually as an accepted content type. Docs for this are here. However, if all your requests are application/json, then no added work should be required on your end as this is default accepted.

blechatellier commented 3 weeks ago

If it's only on the action then the Response object will be returned to the frontend as well, or am I missing something?

IdoPesok commented 3 weeks ago

If it's only on the action then the Response object will be returned to the frontend as well, or am I missing something?

This is true, if you are using the same action in both the router and the frontend. In the latest release you can now define a shapeError on the router that will return a Response. This should fix the issue from 4 messages ago.