Skip to content

How to handle arrays using Zod #1652

@gabrielmar

Description

@gabrielmar

What version of Elysia is running?

1.4.19

What platform is your computer?

No response

What environment are you using

No response

Are you using dynamic mode?

No response

What steps can reproduce the bug?

import { Elysia, t } from 'elysia'
import * as z from 'zod'

export const app = new Elysia()
  .get(
    '/typebox',
    ({ query }) => {
      const { foo } = query
      return { ok: true, foo }
    },
    {
      query: t.Object({
        foo: t.Array(t.String()),
      }),
    },
  )
  .get(
    '/zod',
    ({ query }) => {
      const { foo, bar, baz } = query
      return { ok: true, foo, bar, baz }
    },
    {
      query: z.object({
        foo: z.optional(z.array(z.string())),
        bar: z.optional(
          z
            .string()
            .transform((val) => (Array.isArray(val) ? val : Array.of(val))),
        ),
        baz: z.optional(
          z
            .string()
            .pipe(
              z.transform((val) => (Array.isArray(val) ? val : Array.of(val))),
            ),
        ),
      }),
    },
  )
  .listen(3005, async (server) => {
    console.log(`🦊 Elysia is running at ${server.url.origin}`)
  })
import { describe, expect, it } from 'vitest'

import { treaty } from '@elysiajs/eden'
import { app } from './server'

const api = treaty(app)

describe('Elysia array inconsistency', () => {
  describe('Elysia tests with typebox', () => {
    it('typebox string', async () => {
      const { data, error } = await api.typebox.get({
        query: {
          foo: 'typebox',
        },
      })

      expect(data).toMatchObject({
        ok: true,
        foo: ['typebox'],
      })
      expect(error).toBeNull()
    })

    it('typebox array length 1', async () => {
      const { data, error } = await api.typebox.get({
        query: {
          foo: ['typebox'],
        },
      })

      expect(data).toMatchObject({
        ok: true,
        foo: ['typebox'],
      })
      expect(error).toBeNull()
    })

    it('typebox array length 2', async () => {
      const { data, error } = await api.typebox.get({
        query: {
          foo: ['typebox', 'zod'],
        },
      })

      expect(data).toMatchObject({
        ok: true,
        foo: ['typebox', 'zod'],
      })
      expect(error).toBeNull()
    })
  })

  describe('Elysia tests with zod foo', () => {
    it('zod string', async () => {
      const { data, error } = await api.zod.get({
        query: {
          foo: 'zod',
        },
      })

      expect(data).toMatchObject({
        ok: true,
        foo: ['zod'],
      })
      expect(error).toBeNull()
    })

    it('zod array length 1', async () => {
      const { data, error } = await api.zod.get({
        query: {
          foo: ['zod'],
        },
      })

      expect(data).toMatchObject({
        ok: true,
        foo: ['zod'],
      })
      expect(error).toBeNull()
    })

    it('zod array length 2', async () => {
      const { data, error } = await api.zod.get({
        query: {
          foo: ['zod', 'typebox'],
        },
      })

      expect(data).toMatchObject({
        ok: true,
        foo: ['zod', 'typebox'],
      })
      expect(error).toBeNull()
    })
  })

  describe('Elysia tests with zod bar', () => {
    it('zod string', async () => {
      const { data, error } = await api.zod.get({
        query: {
          bar: 'zod',
        },
      })

      expect(data).toMatchObject({
        ok: true,
        bar: ['zod'],
      })
      expect(error).toBeNull()
    })

    it('zod array length 1', async () => {
      const { data, error } = await api.zod.get({
        query: {
          bar: ['zod'],
        },
      })

      expect(data).toMatchObject({
        ok: true,
        bar: ['zod'],
      })
      expect(error).toBeNull()
    })

    it('zod array length 2', async () => {
      const { data, error } = await api.zod.get({
        query: {
          bar: ['zod', 'typebox'],
        },
      })

      expect(data).toMatchObject({
        ok: true,
        bar: ['zod', 'typebox'],
      })
      expect(error).toBeNull()
    })
  })

  describe('Elysia tests with zod baz', () => {
    it('zod string', async () => {
      const { data, error } = await api.zod.get({
        query: {
          baz: 'zod',
        },
      })

      expect(data).toMatchObject({
        ok: true,
        baz: ['zod'],
      })
      expect(error).toBeNull()
    })

    it('zod array length 1', async () => {
      const { data, error } = await api.zod.get({
        query: {
          baz: ['zod'],
        },
      })

      expect(data).toMatchObject({
        ok: true,
        baz: ['zod'],
      })
      expect(error).toBeNull()
    })

    it('zod array length 2', async () => {
      const { data, error } = await api.zod.get({
        query: {
          baz: ['zod', 'typebox'],
        },
      })

      expect(data).toMatchObject({
        ok: true,
        baz: ['zod', 'typebox'],
      })
      expect(error).toBeNull()
    })
  })
})

What is the expected behavior?

No response

What do you see instead?

✓ Elysia array inconsistency > Elysia tests with typebox > typebox string [13.56ms]
✓ Elysia array inconsistency > Elysia tests with typebox > typebox array length 1 [0.38ms]
✓ Elysia array inconsistency > Elysia tests with typebox > typebox array length 2 [0.32ms]

✗ Elysia array inconsistency > Elysia tests with zod foo > zod string [3.16ms]
✗ Elysia array inconsistency > Elysia tests with zod foo > zod array length 1 [0.38ms]
✓ Elysia array inconsistency > Elysia tests with zod foo > zod array length 2 [0.30ms]

✓ Elysia array inconsistency > Elysia tests with zod bar > zod string [0.37ms]
✓ Elysia array inconsistency > Elysia tests with zod bar > zod array length 1 [0.16ms]
✗ Elysia array inconsistency > Elysia tests with zod bar > zod array length 2 [0.39ms]

✓ Elysia array inconsistency > Elysia tests with zod baz > zod string [0.24ms]
✓ Elysia array inconsistency > Elysia tests with zod baz > zod array length 1 [0.24ms]
✗ Elysia array inconsistency > Elysia tests with zod baz > zod array length 2 [0.34ms]

 8 pass
 4 fail
 20 expect() calls

Additional information

I still haven't found a correct way to pass an array using zod.

I believe this must be a bug, but if I'm wrong, I apologize.

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

No response

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingreviewWaiting for issue reporter approval

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions