Skip to content

A plugin for Nexus that automatically creates object types

License

Notifications You must be signed in to change notification settings

nghiepdev/nexus-mutation

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

52 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

nexus-mutation

NPM version NPM monthly download

A plugin for Nexus that automatically creates object types.

Installation

$ yarn add nexus-mutation

Usage

import {makeSchema} from 'nexus';
import {dynamicMutation, dynamicQuery} from 'nexus-mutation';

// ...
makeSchema({
  plugins: [dynamicMutation(), dynamicQuery()],
});

Basic

Input

import {extendType} from 'nexus';

export const Mutation = extendType({
  type: 'Mutation',
  definition(t) {
    t.dynamicMutation('login', {
      name: 'Login',
      description: 'Handleing Login mutation',
      nonNullDefaults: {
        input: true,
        output: false,
      },
      input(t) {
        t.string('username');
        t.string('password');
      },
      payload(t) {
        t.string('message');
        t.field('user', {
          type: 'User',
        });
      },
      async resolve(_, args, ctx) {
        const {input} = args;
        const user = await fetch('/api/login', {
          method: 'POST',
          body: JSON.stringify(input),
        });

        return {
          message: 'Success!',
          user,
        };
      },
    });
  },
});

Output

type Mutation {
  login(input: LoginInput!): LoginPayload!
}

input LoginInput {
  username: String!
  password: String!
}

type LoginPayload {
  message: String
  user: User
}

Advanced (with Unions)

Handling GraphQL errors like a champ with interfaces and unions

Input

import {extendType, interfaceType, objectType} from 'nexus';

export const ErrorInterface = interfaceType({
  name: 'Error',
  definition(t) {
    t.string('message');
  },
  resolveType() {
    return null;
  },
});

export const Mutation = extendType({
  type: 'Mutation',
  definition(t) {
    t.dynamicMutation('register', {
      name: 'Register',
      input(t) {
        t.string('username');
        t.string('password');
        t.string('fullname');
      },
      payload: {
        result: 'User', // The first type to fallback resolveType
        validationError(t) {
          t.implements('Error');
          t.nullable.string('username');
          t.nullable.string('password');
        },
        countryBlockedError(t) {
          t.implements('Error');
          t.nullable.string('description');
        },
      },
      async resolve(_, args, ctx) {
        const {input} = args;

        if (false === validate(input)) {
          return {
            message: 'Validation input failed',
            username: 'Username has already been taken',
            __typename: 'RegisterValidationError', // Required
          };
        }

        if (false === checkRegion(ctx)) {
          return {
            message: 'Blocked',
            description: 'Registration not available in your region',
            __typename: 'RegisterCountryBlockedError', // Required
          };
        }

        const user = await fetch('/api/user', {
          method: 'POST',
          body: JSON.stringify(input),
        });

        // Fallback
        return user;
      },
    });
  },
});

Output

type Mutation {
  register(input: RegisterInput!): RegisterPayload!
}

input RegisterInput {
  fullname: String
  password: String
  username: String
}

type RegisterCountryBlockedError implements Error {
  description: String
  message: String!
}

type RegisterValidationError implements Error {
  message: String!
  password: String
  username: String
}

union RegisterPayload =
    RegisterCountryBlockedError
  | RegisterValidationError
  | User
mutation Register {
  register(
    input: {username: "johndoe", password: "123456", fullname: "John Doe"}
  ) {
    ... on Error {
      message
    }
    ... on RegisterValidationError {
      username
      password
    }
    ... on RegisterCountryBlockedError {
      description
    }
    ... on User {
      id
      username
      fullname
    }
  }
}

Dynamic Query

Input

import {intArg} from 'nexus';

export const Query = extendType({
  type: 'Query',
  definition(t) {
    t.dynamicQuery('products', {
      name: 'GetProducts',
      args: {
        page: intArg(),
        limit: intArg(),
      },
      result(t) {
        t.string('name');
        t.float('price');
      },
      resultMeta: {
        list: 'list',
        //  pagination: 'Pagination',
      },
      async resolve(_, args, ctx) {
        const {page, limit} = args;
        return {
          items: [{name: 'iPhone 15', price: 1200}],
          // pagination: {
          //   total: 1000,
          // },
        };
      },
    });
  },
});

Output

type GetProductsData {
  name: String
  price: Float
}

type GetProductsResult {
  items: [GetProductsData!]!
  # pagination: 'Pagination',
}

type Query {
  products(page: Int, limit: Int): GetProductsResult!
}

License

MIT

About

A plugin for Nexus that automatically creates object types

Resources

License

Stars

Watchers

Forks

Packages

No packages published