Skip to content
This repository has been archived by the owner on Nov 11, 2018. It is now read-only.

A starter kit for building amazing GraphQL API's with TypeScript and express by @w3tecch

License

Notifications You must be signed in to change notification settings

w3tecch/express-graphql-typescript-boilerplate

Repository files navigation

express-graphql-typescript-boilerplate

Build Status

A GraphQL starter kit for building amazing API's in TypeScript and with Express.js framework.

This seed repository has a complete GraphQL starter kit written in TypeSciprt. For building our API we use various gulp-tasks. We use jasmine and Wallaby for our unit-testing. And there are a lot more awesome features like

  • VSCode tasks and launch configuration
  • Improved GraphQL Error Handling, so that the error stack will be shown in the console
  • Multiple environemnt configurations
  • Basic security configuration
  • Basic cors configuration
  • Basic logger configuration
  • Advanced GraphQL-Context logic, so we can use repos, dataloader and other stuff in each resolver
  • Complete Knex.js integration with seeders and migration
  • DataLoaders
  • Extended GraphQL-Query and GraphQL-Field with a lite Hook-System
  • A lot of examples like:
    • Pagination
    • Search query with filter
    • Custom GraphQL-Types like a date type
    • Migtation and seeders
    • Models
    • Testing examples
    • and many more, just have a look

Getting Started

Prerequisites

Install Node.js

Installing

  • fork this repo
  • clone your fork
  • npm install to install all dependencies
  • npm run install:typings to install all typings
  • Create new database. You will find the name in the src/config.ts file.
  • npm run db:migrate to create the schema
  • npm run db:seed to insert some test data
  • npm run serve to start the dev server in another tab

Running the app

After you have installed all dependencies you can now run the app. Run npm run serve to start a local server using nodemon which will watch for changes and then will restart the sever. The port will be displayed to you as http://0.0.0.0:3000 (or if you prefer IPv6, if you're using express server, then it's http://[::1]:3000/).

Scripts / Commands

Install

  • Install all dependencies with npm install
  • Install all typings with npm run install:typings
  • To install all dependencies and typings use npm run install:dev
  • Remove not needed libraries with npm run install:clean

Linting

  • Run code analysis using npm run lint. This runs tshint.
  • There is also a vscode task for this called lint.

Tests

  • Run the unit tests using npm test or npm run test:pretty for more detailed reporting.
  • There is also a vscode task for this called test.

Running in dev mode

  • Run npm run serve to start nodemon with ts-node, which will serve your app.
  • The server address will be displayed to you as http://0.0.0.0:3000

Cleaning the project

  • Run npm run clean to remove all generated JavaScript files.

Building the project and run it

  • Run npm run build to generated all JavaScript files from your TypeScript sources. After this step you can deploy the app on any server.
  • There is also a vscode task for this called build.
  • To start the builded app use npm start.
  • With npm run zip it will generate the JavaScript source and pack them into to a deployable zip file into the dist folder.

Docs

  • Run npm run docs to generate all doc files and serve it on http://0.0.0.0:8080

Seed

  • Run npm run db:seed to seed some data into the database

Migration

  • Run npm run db:migrate to migration the new schema to the database
  • Run npm run db:migrate:rollback to rollback one version

Exploring the boilerplate

Structure

express-graphql-typescript-boilerplate
 |-- .vscode/                                   * our vscode tasks, launch configuration and some settings
 |-- build/                                     * our task runner configurations and tasks
 |    |-- tasks/                                * gulp tasks
 |    |-- paths.js                              * project path setup for our gulp tasks
 |    |-- util.js                               * our gulp helper functions
 |
 |-- docs/                                      * our generated doc files
 |
 |-- src/                                       * our source files that will be compiled to javascript
 |    |
 |    |-- context/                              * graphql context
 |    |    |-- Context.ts                       * our graphql context class
 |    |    |-- DataloadersContext.ts            * our collection of all dataloaders
 |    |    |-- ServicesContext.ts               * our collection of all repositories
 |    |
 |    |-- core/                                 * our core functionalities
 |    |    |-- Bootstrap.ts                     * our express helper functions to init and run the server
 |    |    |-- Database.ts                      * our database setup
 |    |    |-- Environment.ts                   * gets us the configuration for the given environment
 |    |    |-- GraphQLErrorHandling.ts          * our error handling
 |    |    |-- Logger.ts                        * our logger configurations
 |    |    |-- Server.ts                        * our server error handling
 |    |    |-- Tables.ts                        * our database table names
 |    |    |-- Utils.ts                         * our collection of util functions
 |    |
 |    |-- database/                             * our database tasks
 |    |    |-- factories                        * our factories to create simple fake data
 |    |    |-- migrations                       * our database migration tasks
 |    |    |-- seeds                            * our database seeder tasks
 |    |
 |    |-- exceptions/                           * our errors to throw to the user
 |    |    |-- Exception.ts                     * our basic user error all other errors should inherit from this one
 |    |    |-- NotFoundException.ts             * a basic not found error
 |    |
 |    |-- middlewares/                          * our express custom middlewares (/*.middleware.ts)
 |    |
 |    |-- models/                               * our database models (/*.model.ts)
 |    |
 |    |-- repositories/                         * use a repository to fetch the date of the database
 |    |    |-- **/*Repository.ts
 |    |
 |    |-- services/                             * use a services to separate the logic that retrieves the data and maps it to the entity model from the business logic that acts on the model
 |    |    |-- **/*Services.ts
 |    |
 |    |-- routes/                               * defines our application routes
 |    |    |-- **/*Routes.ts
 |    |
 |    |-- schemas/                              * our graphql schema definitions (use a single file for every graphql object action)
 |    |    |-- arguments/                       * our graphql argument files
 |    |    |-- fields/                          * our graphql field files
 |    |    |-- mutations/                       * our graphql mutation files
 |    |    |-- queries/                         * our graphql query files
 |    |    |-- types/                           * our graphql type files
 |    |
 |    |-- index.ts                              * main entry point for our application
 |    |-- RootValue.ts                          * RootValue with some functions for all the queries and mutations
 |    |-- config.ts                             * has our configuration for our different environments
 |
 |-- test/                                      * our test files that will test our application
 |    |-- mocks                                 * we use this to simulate other functions, classes or objects
 |    |-- unit/**/*.spec.ts                     * our unit test cases
 |
 |-- typings_custom/                            * our local type definitions
 |
 |-- knexfile.ts                                * this has our database configuration from the config.ts
 |-- gulpfile.js                                * entry point for our gulp tasks
 |-- nodemon.json                               * nodemon setup, so that it uses typescript and runs tslint
 |-- package.json                               * what npm uses to manage it's dependencies
 |-- tslint.json                                * typescript lint config
 |-- typedoc.json                               * typescript documentation generator
 |-- tsconfig.json                              * typescript config
 |-- wallaby.js                                 * our wallaby configuration

Hook-System

// We extend the AbstractQuery with the hook system. This
// gives us the 3 new methods called before, run and after.
export class FindAllBooksQuery extends AbstractQuery implements GraphQLFieldConfig {

    public type = new GraphQLList(BookType);
    public allow = ['admin'];
    public args = {
        limit: new LimitArgument(),
        offset: new OffsetArgument()
    };

    // This will be called after the allow checking
    public before(context: Context, args: common.PageinationArguments): Promise<common.PageinationArguments> {
        log.debug('hook before args', args);
        LimitArgument.validate(args.limit);
        OffsetArgument.validate(args.limit);
        return Promise.resolve(args);
    }

    // As long as the before function was okay this will be called afterwards
    public execute(root: RootValue, args: common.PageinationArguments, context: Context): Promise<models.book.Attributes> {
        log.debug('resolve findAllBooks()');
        return context.Repositories.BookRepository.findAllBooks({
            limit: args.limit,
            offset: args.offset
        });
    }

    // And at least before the results go back to our client it will pass this after function
    public after(result: models.book.Attributes, context: Context, args: common.PageinationArguments): Promise<models.book.Attributes> {
        log.debug('hook after args', args);
        return Promise.resolve(result);
    }
}

Related Projects

License

MIT


Made with ♥ by Gery Hirschfeld (@GeryHirschfeld1) and contributors