elysiajs / elysia

Ergonomic Framework for Humans
https://elysiajs.com
MIT License
10.6k stars 226 forks source link

Route param of `group()` must be repeated in nested route schema #913

Open crishoj opened 2 weeks ago

crishoj commented 2 weeks ago

What version of Elysia is running?

1.1.24

What platform is your computer?

Darwin 24.1.0 arm64 arm

What steps can reproduce the bug?

import Elysia, { t } from 'elysia'

export const app = new Elysia()
    // Group with `id` param
    .group('/services/:id', { params: t.Object({ id: t.Number() }) }, (app) => app
        .resolve(({ params: { id } }) => ({ service: { name: `Service ${id}`} }))
        .get('/details', ({ service }) => `Hello from service ${service.name}`)
        // Schema for this route repeats the `id` param - works ✅
        .post('/smooth/:signal', ({ service, params: { signal } }) => `Hello from service ${service.name} signal: ${signal}`,
            { params: t.Object({ signal: t.String(), id: t.Number() }) }
        )
        // Schema for this route doesn't repeat the `id` param - gives HTTP 422 ⚠️
        .post('/trouble/:signal', ({ service, params: { signal } }) => `Hello from service ${service.name} signal: ${signal}`,
            { params: t.Object({ signal: t.String() }) }
        )
    )

for (const [verb, url] of [
    ['GET', 'http://localhost:3000/services/1/details'],
    ['POST', 'http://localhost:3000/services/1/smooth/A'],
    ['POST', 'http://localhost:3000/services/1/trouble/A'],
]) {
    const res = await app.handle(new Request(url, { method: verb }))
    console.log(`${verb} ${url} → ${res.status}: ${await res.text()}`)
}

What is the expected behavior?

It's surprising that the nested routes need to repeat the declaration of the id: t.Number() route parameter, which is already declared in the group.

Expected output:

GET http://localhost:3000/services/1/details → 200: Hello from service Service 1
POST http://localhost:3000/services/1/smooth/A → 200: Hello from service Service 1 signal: A
POST http://localhost:3000/services/1/trouble/A → 200: Hello from service Service 1 signal: A

What do you see instead?

GET http://localhost:3000/services/1/details → 200: Hello from service Service 1
POST http://localhost:3000/services/1/smooth/A → 200: Hello from service Service 1 signal: A
POST http://localhost:3000/services/1/trouble/A → 422: {
  "type": "validation",
  "on": "params",
  "summary": "Property 'id' should not be provided",
  "property": "/id",
  "message": "Unexpected property",
  "expected": {
    "signal": ""
  },
  "found": {
    "signal": "A",
    "id": "1"
  },
  "errors": [
    {
      "type": 42,
      "schema": {
        "type": "object",
        "required": [
          "signal"
        ],
        "properties": {
          "signal": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "path": "/id",
      "value": "1",
      "message": "Unexpected property",
      "summary": "Property 'id' should not be provided"
    }
  ]
}

Additional information

No response

Have you try removing the node_modules and bun.lockb and try again yet?

Yes