elysia icon indicating copy to clipboard operation
elysia copied to clipboard

Schema inheritance/merging between parent and child scopes

Open adicco opened this issue 2 years ago • 2 comments

Let's say you have a wishlist app and the wishlist objects all have items. You want standard CRUD routes on /wishlist/:id but also on /wishlist/:id/items/:item_id

I was trying to come up with a tidy way of reusing the "fetch wishlist" logic which includes not only doing the database call but also imposing some kind of type requirement on the params.

import Elysia, { t } from 'elysia';
const plugin = new Elysia()
  .guard({
    params: t.Object({
      id: t.String(),
    }),
  })
  .derive(async ({ params: { id } }) => {
    const wishlist = async fetchWishlistFromDb(id)
    return { wishlist };
  });
export default plugin;

I would then use this plugin in my route handlers:

const fetchWishlistPugin = require(the plugin above)
app
.use(fetchWishlistPugin)
.get('/wishlist/:id', async({ wishlist }) => { ... })

So far so good. But now let's say I want to implement the child routes for CRUD operations on the wishlist's items. I was doing something like:

const itemsRoutes = new Elysia()
.group('/wishlist/:id', (app) => {
      app
      .use(fetchWishlistPugin)
      .get('/items/:item_id', async({ wishlist, params: { item_id }) => {
         ...
      }, {
            params: t.Object({
              item_id: t.String()
            })
      })
});

I was hoping in my nested routes to have some kind of merge automagically happening on my params schema, but this raises an error that both id and item_id are defined while it is only expecting item_id as params.

Invalid params, 'id': Unexpected property

Expected: {
  "item_id": ""
}

Found: {
  "item_id": "xyb47ihmir7l97weu19ld88x",
  "id": "whatever"
}

Would there be any way of having some inheritance of the schema between parent and child scopes, and if not, how would one model such a case? It would feel neat to be able to encapsulate in a plugin the fetching of the wishlist along with its params' (or others, say body) requirements. Thanks!

adicco avatar Oct 01 '23 15:10 adicco

To fix my particular issue one can use typebox's additionalProperties:

params: t.Object({
  item_id: t.String()
}, { additionalProperties: true })

But I am still wondering if there might be cases where merging/accessing the parent scope would be helpful?

adicco avatar Oct 01 '23 15:10 adicco

We are using Elysia in a project I'm working on and because of requirements of our project, we use a lot of grouped routes with params on it. We were creating the params schemas with the group that introduced the param, but we quickly faced the problem described in this issue. To not face this problem we have to either use additionalProperties: true as described above, but we lose type inference for other paams, or repeat the params schema in each route that adds a new param, which is tedious, repetitive and makes the code hard to refactor. So, being able to merge/access the parent scope of the params schema would be really helpful to us.

davi-i avatar Apr 02 '24 07:04 davi-i

Closing as resolve by introduction of response reconcilation.

If the issue still happens, feels free to reopen the issue.

SaltyAom avatar Aug 30 '24 11:08 SaltyAom