ecyrbe / zodios

typescript http client and server with zod validation
https://www.zodios.org/
MIT License
1.59k stars 44 forks source link

Response type is different in @zodios/express from the makeApi types endpoints. #557

Closed razb-viola closed 7 months ago

razb-viola commented 7 months ago

I have made this endpoint, using the makeApi function:

// common module

export const Account = z.object({
  firstName: z.string()
})
export const endpoints = makeApi([
  {
    method: "get",
    path: "/accounts",
    alias: "getAccounts",
    description: `Get accounts`,
    requestFormat: "json",
    response: Account,
  },
])

According to the code above, if you go to GET /accounts, you will get a response of an Account.

Now lets implement this:

// express server

import { zodiosApp } from '@zodios/express'
import { endpoints } from '../common/zodios-client'
import { z } from 'zod'

const app = zodiosApp(endpoints)

const account: z.infer<typeof Account> = {
  firstName: 'raz'
}

app.get('/accounts', (req, res) => {
  res.json(account); // typescript will shout on me
})

So we defined an endpoint using zodios and then used it in the actual implementation of the express app. But we got a TypeScript error here since the returned object is not of type of the res.json.

The return type that is expected to be sent using the res.json is literal string, instead of the type/interface of the Account. Which leads to type errors in TypeScript.

What can we do here in order to make this works? In short, the returned type of the express endpoint is different from the makeApi type.

If I send the Account explicitly it will work:

res.json({ firstName: 'raz' })

Since the res.json type is formatted like this: firstName: ZodString and the Account is formatted like this: firstName: string which are probably not the same in the TypeScript point of view.