elierotenberg / fastify-zod

Zod integration with Fastify
MIT License
212 stars 19 forks source link

FastifyError: Schema with id 'Schema' already declared! #8

Closed xeusteerapat closed 2 years ago

xeusteerapat commented 2 years ago

I got an error when using fastify-zod version 1.0.0-rc10. Here are code examples,

// productSchemas
import { z } from 'zod';
import { buildJsonSchemas } from 'fastify-zod';

const productInput = {
  title: z.string(),
  price: z.number(),
  content: z.string().optional(),
};

const productGenerated = {
  id: z.number(),
  createdAt: z.string(),
  updatedAt: z.string(),
};

const createProductSchema = z.object({
  ...productInput,
});

const productResponseSchema = z.object({
  ...productInput,
  ...productGenerated,
});

const productsResponseSchema = z.array(productResponseSchema);

export type CreateProductInput = z.infer<typeof createProductSchema>;

export const { schemas: productSchemas, $ref } = buildJsonSchemas({
  createProductSchema,
  productResponseSchema,
  productsResponseSchema,
});

and userSchemas

import { z } from 'zod';
import { buildJsonSchemas } from 'fastify-zod';

const userCoreSchema = {
  email: z
    .string({
      required_error: 'Email is required',
      invalid_type_error: 'Email must be a string',
    })
    .email(),
  name: z.string(),
};

const createUserSchema = z.object({
  ...userCoreSchema,
  password: z.string({
    required_error: 'Password is required',
    invalid_type_error: 'Password must be a string',
  }),
});

const createUserResponseSchema = z.object({
  ...userCoreSchema,
  id: z.number(),
});

const loginSchema = z.object({
  email: z
    .string({
      required_error: 'Email is required',
      invalid_type_error: 'Email must be a string',
    })
    .email(),
  password: z.string(),
});

const loginResponseSchema = z.object({
  accessToken: z.string(),
});

export type CreateUserInputSchema = z.infer<typeof createUserSchema>;
export type LoginInputSchema = z.infer<typeof loginSchema>;

export const { schemas: userSchemas, $ref } = buildJsonSchemas({
  createUserSchema,
  createUserResponseSchema,
  loginSchema,
  loginResponseSchema,
});

the result is both schemas create the same $id property. See picture below Screen Shot 2565-04-25 at 16 12 56

Knorway commented 2 years ago

I resolved this with adding an option to specify the schema $id

export const { schemas: postSchemas, $ref } = buildJsonSchemas(
    {
        findPostByIdInputSchema,
        findPostsResponseSchema,
    },
    {
        $id: 'postSchemas',
    }
);
xeusteerapat commented 2 years ago

@Knorway I've tried this before. It worked but got another Typescript error when I use withRefResolver with fastify-swagger

import swagger from 'fastify-swagger';
import { withRefResolver } from 'fastify-zod';

then register plugin

server.register(
    swagger,
    withRefResolver({
      routePrefix: '/docs',
      exposeRoute: true,
      staticCSP: true,
      openapi: {
        info: {
          title: 'Fastify API',
          description: 'Example API created from Fastify and Prisma',
          version,
        },
      },
    })
  );

then, got big complain from TS

No overload matches this call.
  Overload 1 of 3, '(plugin: FastifyPluginCallback<SwaggerOptions, Server>, opts?: FastifyRegisterOptions<SwaggerOptions> | undefined): FastifyInstance<...> & PromiseLike<...>', gave the following error.
    Argument of type 'FastifyDynamicSwaggerOptions' is not assignable to parameter of type 'FastifyRegisterOptions<SwaggerOptions> | undefined'.
      Type 'FastifyDynamicSwaggerOptions' is not assignable to type 'RegisterOptions & FastifyDynamicSwaggerOptions'.
        Type 'import("/Users/teerapatprommarak/Project/nodejs/prisma-project/fastify-prisma-mysql/node_modules/fastify-zod/node_modules/fastify-swagger/index").FastifyDynamicSwaggerOptions' is not assignable to type 'import("/Users/teerapatprommarak/Project/nodejs/prisma-project/fastify-prisma-mysql/node_modules/fastify-swagger/index").FastifyDynamicSwaggerOptions'.
          Types of property 'transform' are incompatible.
            Type 'Function | undefined' is not assignable to type '(<S extends FastifySchema = FastifySchema>({ schema, url }: { schema: S; url: string; }) => { schema: JSONObject; url: string; }) | undefined'.
              Type 'Function' is not assignable to type '<S extends FastifySchema = FastifySchema>({ schema, url }: { schema: S; url: string; }) => { schema: JSONObject; url: string; }'.
                Type 'Function' provides no match for the signature '<S extends FastifySchema = FastifySchema>({ schema, url }: { schema: S; url: string; }): { schema: JSONObject; url: string; }'.
  Overload 2 of 3, '(plugin: FastifyPluginAsync<SwaggerOptions, Server>, opts?: FastifyRegisterOptions<SwaggerOptions> | undefined): FastifyInstance<...> & PromiseLike<...>', gave the following error.
    Argument of type 'FastifyPluginCallback<SwaggerOptions, Server>' is not assignable to parameter of type 'FastifyPluginAsync<SwaggerOptions, Server>'.
  Overload 3 of 3, '(plugin: FastifyPluginCallback<SwaggerOptions, Server> | FastifyPluginAsync<SwaggerOptions, Server> | Promise<...> | Promise<...>, opts?: FastifyRegisterOptions<...> | undefined): FastifyInstance<...> & PromiseLike<...>', gave the following error.
    Argument of type 'FastifyDynamicSwaggerOptions' is not assignable to parameter of type 'FastifyRegisterOptions<SwaggerOptions> | undefined'.ts(2769)
elierotenberg commented 2 years ago

Hello,

I'm sorry, as mentioned in #15 for some reason GitHub notifications got lost in my mailbox.

I have failed to reproduce the issue but added a test here.

Would you please elaborate or add a failing test?

Thank you.

xeusteerapat commented 2 years ago

@elierotenberg How to install and package locally? I've tried yarn but it asked for test-openapi-client file.

error Package "fastify-zod-test-openapi-client" refers to a non-existing file '"/Users/teerapatprommarak/Project/explore/fastify-zod/test-openapi-client"'.

elierotenberg commented 2 years ago

I've added a postinstall script which should solve this issue.

Can you please confirm this works for you?

Thanks.