Skip to content

GraphQL API Framework with strong conventions and auto-generated schema

License

Notifications You must be signed in to change notification settings

deweyjose/warthog

 
 

Repository files navigation

Warthog - GraphQL API Framework

npm version CircleCI styled with prettier semantic-release Join the chat at https://gitter.im/warthog-graphql/community

Opinionated framework for building GraphQL APIs with strong conventions. With Warthog, set up your data models and the following are automatically generated:

  • Database schema - generated by TypeORM
  • Your entire GraphQL Schema including:
    • types to match your entities - generated by TypeGraphQL
    • GraphQL inputs for consistent creates, updates, filtering, and pagination inspired by Prisma's conventions
  • A graphql-binding for type-safe programmatic access to your APIs.
  • TypeScript classes for the generated GraphQL schema for type-safety while developing.
  • Automatic validation before data is saved using any of the decorators available in the class-validator library.

Warning

The API for this library is still subject to change. It will likely shift until version 2, at which time it will become stable. I'd love early adopters, but please know that there might be some breaking changes for a few more weeks.

Prerequisites

You must have Postgresql installed to use Warthog. If you're on OSX and have Homebrew installed, you can simply run:

brew install postgresql

Otherwise, you can install Postgres.app or use the Google machine to figure out how to install on your OS.

Usage

The easiest way to start using Warthog for a fresh project is to clone the warthog-starter repo. This has a simple example in place to get you started. There are also a bunch of examples in the examples folder for more advanced use cases.

Note that the examples in the examples folder use relative import paths to call into Warthog. In your projects, you won't need to set this config value as it's only set to deal with the fact that it's using the Warthog core files without consuming the package from NPM. In your projects, you can omit this as I do in warthog-starter.

Installing in Existing Project

yarn add warthog

1. Create a Model

The model will auto-generate your database table and graphql types. Warthog will find all models that match the following glob - '/**/*.model.ts'. So for this file, you would name it user.model.ts

import { BaseModel, Model, StringField } from 'warthog';

@Model()
export class User extends BaseModel {
  @StringField()
  name?: string;
}

2. Create a Resolver

The resolver auto-generates queries and mutations in your GraphQL schema. Warthog will find all resolvers that match the following glob - '/**/*.resolver.ts'. So for this file, you would name it user.resolver.ts

import { User } from './user.model';

@Resolver(User)
export class UserResolver extends BaseResolver<User> {
  constructor(@InjectRepository(User) private readonly userRepository: Repository<User>) {
    super(User, userRepository);
  }

  @Query(returns => [User])
  async users(
    @Args() { where, orderBy, limit, offset }: UserWhereArgs
  ): Promise<User[]> {
    return this.find<UserWhereInput>(where, orderBy, limit, offset);
  }

  @Mutation(returns => User)
  async createUser(@Arg('data') data: UserCreateInput, @Ctx() ctx: BaseContext): Promise<User> {
    return this.create(data, ctx.user.id);
  }
}

3. Add config to .env file

APP_HOST=localhost
APP_PORT=4100
TYPEORM_DATABASE=warthog
TYPEORM_USERNAME=postgres
TYPEORM_PASSWORD=

4. Run your server

import 'reflect-metadata';
import { Server } from 'warthog';

async function bootstrap() {
  const server = new Server();
  return server.start();
}

bootstrap()

When you start your server, there will be a new generated folder that has your GraphQL schema in schema.graphql. This contains:

type User implements BaseGraphQLObject {
  id: String!
  createdAt: DateTime!
  createdById: String!
  updatedAt: DateTime
  updatedById: String
  deletedAt: DateTime
  deletedById: String
  version: Int!
  name: String!
}

input UserCreateInput {
  name: String!
}

enum UserOrderByInput {
  createdAt_ASC
  createdAt_DESC
  updatedAt_ASC
  updatedAt_DESC
  deletedAt_ASC
  deletedAt_DESC
  name_ASC
  name_DESC
}

input UserUpdateInput {
  name: String
}

input UserWhereInput {
  id_eq: String
  id_in: [String!]
  createdAt_eq: String
  createdAt_lt: String
  createdAt_lte: String
  createdAt_gt: String
  createdAt_gte: String
  createdById_eq: String
  updatedAt_eq: String
  updatedAt_lt: String
  updatedAt_lte: String
  updatedAt_gt: String
  updatedAt_gte: String
  updatedById_eq: String
  deletedAt_all: Boolean
  deletedAt_eq: String
  deletedAt_lt: String
  deletedAt_lte: String
  deletedAt_gt: String
  deletedAt_gte: String
  deletedById_eq: String
  name_eq: String
  name_contains: String
  name_startsWith: String
  name_endsWith: String
  name_in: [String!]
}

input UserWhereUniqueInput {
  id: String!
}

Notice how we've only added a single field on the model and you get pagination, filtering and tracking of who created, updated and deleted records automatically.

Server API

App Options (appOptions)

attribute description default
container TypeDI container. Warthog uses dependency injection under the hood. empty container
authChecker An instance of an AuthChecker to secure your resolvers.
autoGenerateFiles Should the server auto-generate your schema, typings, etc... true when NODE_ENV=development. false otherwise
context Context getter of form (request: Request) => object empty
generatedFolder Folder where generated content is created process.cwd() + 'generated'
logger Logger debug
middlewares Express middlewares to add to your server none
mockDBConnection Opens a sqlite connection instead of Postgres. Helpful if you just need to generate the schema false
openPlayground Should server open GraphQL Playground after starting? false if running tests, true if in development mode
port App Server Port 4000
resolversPath Glob path to find your resolvers process.cwd() + '/**/*.resolver.ts'

Config

All config is driven by environment variables. Most options can also be set by setting the value when creating your Server instance.

variable value config option name default
APP_HOST App server host appOptions.host none
APP_PORT App server port appOptions.port 4000
TYPEORM_DATABASE DB name none none
TYPEORM_USERNAME DB username none none
TYPEORM_PASSWORD DB password none none

Intentionally Opinionated

Warthog is intentionally opinionated to accelerate development and make use of technology-specific features:

  • Postgres - currently the only database supported. This could be changed, but choosing Postgres allows adding a docker container and other goodies easily.
  • Jest - other harnesses will work, but if you use Jest, we will not open the GraphQL playground when the server starts, for example.
  • Soft deletes - no records are ever deleted, only "soft deleted". The base service used in resolvers filters out the deleted records by default.

Thanks

Special thanks to the authors of:

Warthog is essentially a really opinionated composition of TypeORM and TypeGraphQL that uses similar GraphQL conventions to the Prisma project.

Contribute

PRs accepted, fire away! Or add issues if you have use cases Warthog doesn't cover.

License

MIT © Dan Caddigan

About

GraphQL API Framework with strong conventions and auto-generated schema

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • TypeScript 100.0%