Skip to content

Create gql and mongoose schema using a single source at the same time

License

Notifications You must be signed in to change notification settings

mavvystudio/mgql

Repository files navigation

Mongoose + Graphql + Apollo all in one

Creating graphql server just got easier

Getting Started

Installation

install dependencies

npm install @mavvy/mgql @apollo/server mongoose graphql

Example

see examples directory examples

Or check the Code Sandbox example

What is MGql?

Basically it generates mongoose schema and graphql schema at the same time from a model array data. Also, it helps create resolvers with additional helpers that has automatic integration to the database.

Object model to mongoose and graphql schema

This will be transformed into a mongoose and graphql schema

[
  {
    name: 'Comment',
    fields: {
      body: String,
      date: Date,
    },
  },
  {
    name: 'Blog',
    fields: {
      title: String, // String is shorthand for {type: String}
      author: String,
      body: String,
      comments: [
        {
          _gql: '[Comment]',
          body: String,
          date: Date,
        },
      ],
      hidden: Boolean,
      meta: {
        _gql: 'Meta',
        votes: Number,
        favs: Number,
      },
    },
  },
]

the above code will create this gql schema below:

type Comment {
  body: String
  date: String
  createdAt: Float
  updatedAt: Float
  deletedAt: Float
  isDeleted: Boolean
  id: ID
}

type Meta {
  votes: Int
  favs: Int
  createdAt: Float
  updatedAt: Float
  deletedAt: Float
  isDeleted: Boolean
  id: ID
}

type Blog {
  title: String
  author: String
  body: String
  comments: [Comment]
  hidden: Boolean
  meta: Meta
  createdAt: Float
  updatedAt: Float
  deletedAt: Float
  isDeleted: Boolean
  id: ID
}

And then will create mongoose schema for Comment and Blog

Usage

import 'dotenv/config';
import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';
import * as mgql from '@mavvy/mgql';

const uri = process.env.MONGO_URI as string;
const models = [
  {
    name: 'Comment',
    fields: {
      body: String,
      date: Date,
    },
  },
  {
    name: 'Blog',
    fields: {
      title: String, // String is shorthand for {type: String}
      author: String,
      body: String,
      comments: [
        {
          _gql: '[Comment]',
          body: String,
          date: Date,
        },
      ],
      hidden: Boolean,
      meta: {
        _gql: 'Meta',
        votes: Number,
        favs: Number,
      },
    },
  },
];
const resolvers = [
  {
    name: 'blogs',
    model: 'Blog',
    resolverType: 'Query',
    handler: async ({ model }) => model().find(),
    returnType: '[Blog]',
  },
  {
    name: 'addBlog',
    model: 'Blog',
    resolverType: 'Mutation',
    handler: ({ actions, input }) => actions.create(input),
    inputVariable: 'CreateBlogInput!',
    returnType: 'Blog',
  },
  {
    name: 'addComment',
    model: 'Comment',
    resolverType: 'Mutation',
    inputVariable: 'AddCommentInput!',
    handler: async ({ model, actions, input }) => {
      const blogModel = model('Blog');
      const blog = await blogModel.findById(input.blogId);
      const comment = await actions.create({ body: input.body });

      blog.comments.push(comment);

      await blog.save();

      return comment;
    },
    returnType: 'Comment',
  },
] as mgql.MgqlResolvers[];

const appSchema = `input CreateBlogInput {
  title: String!
  author: String!
  body: String!
}

input AddCommentInput {
  blogId: ID!
  body: String!
}`;

const main = async () => {
  const modelSchema = mgql.toSchema(models);
  await mgql.initDb({ uri, models });

  const schema = mgql.createSchema(
    [appSchema].concat(modelSchema),
    resolvers,
    models,
  );

  const server = new ApolloServer({
    typeDefs: schema.typeDefs,
    resolvers: schema.resolvers,
  });

  const { url } = await startStandaloneServer(server, {
    listen: { port: 4000 },
  });

  console.log(`πŸš€  Server ready at: ${url}`);
};

main();

API

Models

key type description
name string name of the mongoose schema
fields object properties of the schema. The shape of the documents within that collection
Model Field Item Attributes
_gql: string

Graphql schema to apply to the field item

{
  name: 'Blog',
  fields: {
    author: {
      _gql: 'Author',
      name: String
    }
  }
}

will generate:

type Author {
  name: String
}
type Blog {
  author: Author
}
_hidden: boolean

Will not generate a gql schema for that field item

{
  name: 'Blog',
  fields: {
    title: String,
    author: {
      _gql: 'Author',
      _hidden: true,
      name: String
    }
  }
}

will generate:

type Blog {
  title: String
}
_omit: string[]

will not generate gql fields which are listed on the _omit field

{
  name: 'Blog',
  fields: {
    author: {
      _gql: 'Author',
      _omit: ['foo', 'bar'],
      name: String
      foo: String
      bar: String
    }
  }
}

will generate:

type Author {
  name: String
}
type Blog {
  author: Author
}
_override: boolean

Nested objects will automatically generate a schema type. If you don't want to override the schema type, set _override to true

[
  {
    name: 'User',
    fields: {
      name: String
    }
  },
  {
    name: 'Project',
    fields: {
      todo: {
        _gql: 'Todo',
        user: {
          _gql: 'User',
          _override: true,
          nickname: String
        },
        tag: {
          _gql: 'Tag',
          name: String
        }
      }
    }
  }
]

Will generate gql schema:

type User {
  nickname: String
}
type Tag {
  name: String
}
type Todo {
  user: User
  tag: Tag
}
type Project {
  todo: Todo
}

Resolvers

A resolver item is a configuration to create a Query or Mutation (Subscriptions soon).

key type description
name string name of the resolver
model string? name of the mongoose model to use inside the handler
resolverType Query | Mutation type of the resolver
returnType string Schema name of the return data
inputVariable string? Schema name of the input
disabled boolean? disables the resolver
roles string[]? array of roles that is authorized to use the resolver
handler (handlerArgs) => any the main resolver function
handlerArgs object
key description
parentContext resolver.parentContext param from apolo
variables resolver.variables param from apollo
context resolver.context param from apollo
options resolver options such as model name, returnType, etc.
input shorthand to return the value from variables.input
model (name?: string) => mongoose.Model . the default name is the model name value from the resolver
actions actions.create is use to add data to db. actions.search is use to find data from the db

About

Create gql and mongoose schema using a single source at the same time

Topics

Resources

License

Stars

Watchers

Forks

Sponsor this project

Packages

No packages published

Contributors 3

  •  
  •  
  •