Giter Site home page Giter Site logo

matt-koevort / nestjs-graphql-zod Goto Github PK

View Code? Open in Web Editor NEW

This project forked from incetarik/nestjs-graphql-zod

1.0 1.0 0.0 93 KB

A library providing dynamic GraphQL object classes from their zod validation objects.

License: Mozilla Public License 2.0

TypeScript 100.00%

nestjs-graphql-zod's Introduction

nestjs-graphql-zod

Use zod validation objects in your GraphQL actions!

This library provides utility functions and decorators similar to NestJS GraphQL decorators that lets you work with zod objects without the need of writing GraphQL schema classes.

  • Nested zod.object(...) calls are supported. These will lead to generate another GraphQL model for each definition.

  • Descriptions are supported. Additionally, for zod.object(...) definitions, to provide a custom name (instead of the dynamically generated ones) the description should be in {ClassName}:{Description} format (for example UpdateModel: Contains properties that will be updated). This will cause a model generation with given class name with given description.

  • zod.enum(...) calls are supported. Enum models will be generated in GraphQL schema.

Decorators

All the decorators are the same with underlying decorator with an exception that the first parameter is the zod object.

The overloads of the underlying decorators are also reflected. Therefore it is possible to use an overload of the decorators provided by this library.

Method Decorators:

  • @QueryWithZod
  • @MutationWithZod
  • @SubscriptionWithZod

These decorators will do output validation. They take zod object and validate the output with given zod object.

Parameter/Class Decorators

  • @ZodArgs
  • @InputTypeWithZod

These decorators will do input validation. They take zod object and validate the input with given zod object.

Utility Functions

  • modelFromZodBase: Takes a zod input, options and a decorator to decorate the dynamically built class with (such as ObjectType).

  • modelFromZod: Takes a zod input and options to build an ObjectType decorated class and return the class itself. The class will contain the properties from the given zod input.

  • inputFromZod: Takes a zod input and options to build an InputType decorated class and return the class itself. The class will contain the properties from the given zod input.

  • getZodObject: Takes an object and returns the source zod object that is used to build the class. For this function to return a defined value, the classes should be built with keepZodObject option property set to true.


Setup

  • Add nestjs-graphql-zod to your dependencies in package.json.
  • Either use:
    • Classes which you can create with modelFromZod.

    • Use decorators for GraphQL action methods:

      • @MutationWithZod
      • @QueryWithZod
      • @SubscriptionWithZod

      or decorators for parameters:

      • @ZodArgs

      These are the same with their corresponding GraphQL method decorators. Yet, they work with zod objects.

Example

Simple

import * as zod from 'zod'

const UserZod = zod.object({
  name: zod.string().describe('The name of the user'),
  age: zod.number().int().gt(10).describe('The age of the user.'),
  fields: zod.string().optional().array().optional().describe('The fields of the user'),
  sortBy: zod.enum([ 'asc', 'desc' ]).describe('The sorting parameter of user.')
}).describe('ExampleUser: Represents an example user instance.')

class UserResolver {
  @QueryWithZod(UserZod)
  async getUser() {
    // You can simply return an object to be parsed and if the parsing is
    // successful, then the data will be returned, otherwise an error will
    // be thrown.

    return {
      name: 'User Name',
      age: 15,
      fields: [ 'Field 1', 'Field 2' ],
      sortBy: 'asc'
    }
  }
}

With the example above, you will have the following generated GraphQL schema type if you use code-first approach:

""" Represents an example user instance."""
type ExampleUser {
  """The name of the user"""
  name: String!

  """The age of the user."""
  age: Int!

  """The fields of the user"""
  fields: [String]

  """The sorting parameter of user."""
  sortBy: ExampleUser_SortByEnum_0!
}

"""The sorting parameter of user."""
enum ExampleUser_SortByEnum_0 {
  asc
  desc
}

Nested Object

import * as zod from 'zod'

const UserZod = zod.object({
  name: zod.string().describe('The name of the user'),
  age: zod.number().int().gt(10).describe('The age of the user.'),
  fields: zod.string().optional().array().optional().describe('The fields of the user'),
  sortBy: zod.enum([ 'asc', 'desc' ]).describe('The sorting parameter of user.'),
  settings: zod.object({
    darkTheme: zod.boolean().optional().describe('The dark theme setting'),
    ratio: zod.number().describe('This will be float by default'),
    profile: zod.object({
      showImage: zod.boolean().describe('Indicates whether the user is showing images.'),
    }).describe('UserProfileSetting: Represents user profile settings.'),
  }).describe('ExampleUserSettings: The user settings.'),
}).describe('ExampleUser: Represents an example user instance.')

class UserResolver {
  @QueryWithZod(UserZod)
  async getUser() {
    // You can simply return an object to be parsed and if the parsing is
    // successful, then the data will be returned, otherwise an error will
    // be thrown.

    return {
      name: 'User Name',
      age: 15,
      fields: [ 'Field 1', 'Field 2' ],
      sortBy: 'asc',
      settings: {
        darkTheme: false,
        ratio: 2.5,
        profile: {
          showImage: true
        }
      }
    }
  }
}

With the example above, you will have the following generated GraphQL schema type if you use code-first approach:

""" Represents an example user instance."""
type ExampleUser {
  """The name of the user"""
  name: String!

  """The age of the user."""
  age: Int!

  """The fields of the user"""
  fields: [String]

  """The sorting parameter of user."""
  sortBy: ExampleUser_SortByEnum_0!

  """ExampleUserSettings: The user settings."""
  settings: ExampleUser_Settings!
}

"""The sorting parameter of user."""
enum ExampleUser_SortByEnum_0 {
  asc
  desc
}

"""ExampleUserSettings: The user settings."""
type ExampleUser_Settings {
  """The dark theme setting"""
  darkTheme: Boolean

  """This will be float by default"""
  ratio: Float!

  """UserProfileSetting: Represents user profile settings."""
  profile: ExampleUser_Settings_Profile!
}

"""UserProfileSetting: Represents user profile settings."""
type ExampleUser_Settings_Profile {
  """Indicates whether the user is showing images."""
  showImage: Boolean!
}

InputType/Args Example

import * as zod from 'zod'
import { ZodArgs } from 'nestjs-graphql-zod'

const RequestSchema = zod.object({
  username: zod.string().min(5).max(20).describe('The username of the request owner'),
  email: zod.string().email().describe('The email of the user'),
  changes: zod.object({
    themeSelection: zod.enum([ 'light', 'dark' ]).describe('The theme type'),
    permissions: zod.object({
      add: zod.number().array().describe('The flags added to the user permissions'),
      remove: zod.number().array().describe('The flags removed to the user permissions'),
      isAdmin: zod.boolean().describe('Indicates if the user is an admin')
    }).describe('The permissions change set of the user')
  }).describe('The changes made by the user')
}).describe('RequestSchema: The request schema type for changing user data')

class ExampleResolver() {
  @Query(() => Boolean)
  processRequest(@ZodArgs(RequestSchema) input: ZodArgs.Of<typeof RequestSchema>) {
    // The input will contain all the properties validated according to the
    // schema defined above. If the validation was failed, the user will get
    // BadRequest error and this method will not be called.

    // The @ZodArgs(Schema) decorator is behaving like 
    // @Args() + @InputType() decorators.
    //
    // The @InputType() is applied to underlying class, the @Args() is applied
    // to take the input as the parameter. By default, the name of the
    // property will be 'input'. This can be changed through the overloads
    // of the decorator.
  }
}

With the example above, you will have the following generated GraphQL schema type if you use code-first approach:

"""The request schema type for changing user data"""
input RequestSchema {
  """The username of the request owner"""
  username: String!

  """The email of the user"""
  email: String!

  """The changes made by the user"""
  changes: RequestSchema_Changes!
}

"""The request schema type for changing user data"""
input RequestSchema_Changes {
  """The theme type"""
  themeSelection: RequestSchema_Changes_ThemeSelectionEnum_0!

  """The permissions change set of the user"""
  permissions: RequestSchema_Changes_Permissions!
}

"""The theme type"""
enum RequestSchema_Changes_ThemeSelectionEnum_0 {
  light
  dark
}

"""The request schema type for changing user data"""
input RequestSchema_Changes_Permissions {
  """The flags added to the user permissions"""
  add: [Float!]!

  """The flags removed to the user permissions"""
  remove: [Float!]!

  """Indicates if the user is an admin"""
  isAdmin: Boolean!
}

Support

To support the project, you can send donations to following addresses:

- Bitcoin     : bc1qtut2ss8udkr68p6k6axd0na6nhvngm5dqlyhtn
- Bitcoin Cash: qzmmv43ztae0tfsjx8zf4wwnq3uk6k7zzgcfr9jruk
- Ether       : 0xf542BED91d0218D9c195286e660da2275EF8eC84

nestjs-graphql-zod's People

Contributors

incetarik avatar

Stargazers

 avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.