Home

Awesome

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

Getting Started

Prerequisites

Install Node.js

Installing

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

Linting

Tests

Running in dev mode

Cleaning the project

Building the project and run it

Docs

Seed

Migration

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