• Stars
    star
    322
  • Rank 130,398 (Top 3 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created about 8 years ago
  • Updated over 6 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Generate your GraphQL server one type at a time

Create GraphQL Server

Create-graphql-server is a scaffolding tool that lets you generate a new Mongo/Express/Node.js GraphQL server project from the command line. After generating the project you can also generate code to support your GraphQL schema directly from the schema files. Basic authentication support is included via Passport Local with JWTs.

NOTE: this project is not actively maintained. As a scaffolding tool, this is not necessarily an issue (you can generate a project with it and then forget about the tool), but it is increasingly falling out of date. A spritiual successor is the graphql-cli project. Please take a look!

Getting Started

Installation

Install it once globally:

npm install -g create-graphql-server

Creating a Server

To create a new server in the my-new-server-dir folder use the init command:

create-graphql-server init my-new-server-dir
cd my-new-server-dir
yarn install

Starting the Server

In most development environments you can now fire up your new server using the packaged prebuilt Mongo server:

yarn start

If mongo-prebuilt fails to start, or you'd rather use another MongoDB installation for development, simply set the MONGO_URL environment variable when you start the server, as follows:

# On Windows:
SET MONGO_URL=mongodb://localhost:27017&&yarn start

# On Unix/OSX:
MONGO_URL=mongodb://localhost:27017 yarn start

If you set up a username, password or a different port for Mongo, or are accessing Mongo through a service such as mLab, correct the MONGO_URL above to reflect that.

Running Queries

Your server is now up and running. To query it, point your browser at http://localhost:3010/graphiql. There isn't anything to query yet however.

Adding Types: Overview

To add types, you can define them in GraphQL schema files, then generate code for them using the add-type command, as follows:

create-graphql-server add-type path/to/my-new-type.graphql

If you have a folder full of schema files, you can add them all at once by pointing add-type to a folder instead of an individual schema file:

create-graphql-server add-type path

Sample schema files are included in test/input. To see what a complete generated server looks like using them, check out test/output-app.

Schemas

You create a GraphQL type for your schema by specifying the type as input, with some special code-generation controlling directives.

For example, in User.graphql:

type User {
  email: String!
  bio: String

  tweets: [Tweet!] @hasMany(as: "author")
  liked: [Tweet!] @belongsToMany

  following: [User!] @belongsToMany
  followers: [User!] @hasAndBelongsToMany(as: "following")
}

The above will generate a User type which is linked to other users and a tweet type via foriegn keys and which will have mutations to add, update and remove users, as well as some root queries to find a single user or all users.

The directives used control the code generation (see below).

Directives

  • @unmodifiable - the field will not appear in the update mutation
  • @enum - the field's type is an enum, and can be set directly (not just by Id).

Relations

If types reference each other, you should use an association directive to explain to the generator how the reference should be stored in mongo:

Singleton fields

If the field references a single (nullable or otherwise) instance of another type, it will be either:

  • @belongsTo - the foreign key is stored on this type as ${fieldName}Id [this is the default]
  • @hasOne - the foreign key is stored on the referenced type as ${typeName}Id. Provide the "as": X argument if the name is different. [NOTE: this is not yet fully implemented].

Paginated fields

If the field references an array (again w/ or w/o nullability) of another type, it will be either:

  • @belongsToMany - there is a list of foreign keys stored on this type as ${fieldName}Ids [this is the default]
  • @hasMany - the foreign key is on the referenced type as ${typeName}Id. Provide the "as": X argument if the name is different. (this is the reverse of @belongsTo in a 1-many situation).
  • @hasAndBelongsToMany - the foreign key on the referenced type as ${typeName}Ids. Provide the "as": X argument if the name is different. (this is the reverse of @belongsToMany in a many-many situation).

Updating types

To update types, just re-run add-type again:

create-graphql-server add-type path/to/input.graphql [--force-update]

This overwrites your old type specific files from the directories: schema, model, resolvers.

It recognizes, if you've changed any code file, which will be overwritten by the generator and stops and warns. If you are sure, you want to overwrite your changes, then just use the --force-update option.

Removing types

To remove types, use the following command with the path to the GraphQL file, or as alternative, just enter the type name without path.

create-graphql-server remove-type path/to/input.graphql

create-graphql-server remove-type typename

create-graphql-server remove-type path

This command deletes your old type specific files from the directories: schema, model, resolvers. It also removes the code references out of the corresponding index files.

It recognizes, if you've changed any code file, which will be overwritten by the generator and stops and warns. If you are sure, you want to overwrite your changes, then just use the force-update option.

Authentication

CGS sets up a basic passport-based JWT authentication system for your app.

NOTE: you should ensure users connect to your server through SSL.

To use it, ensure you have a GraphQL type called User in your schema, with a field email, by which users will be looked up. When creating users, ensure that a bcrypted hash database field is set. For instance, if you created your users in this way:

type User {
  email: String!
  bio: String
}

You could update the generated CreateUserInput input object to take a password field:

input CreateUserInput {
  email: String!
  password: String! # <- you need to add this line to the generated output
  bio: String
}

And then update the generated User model to hash that password and store it:

import bcrypt from 'bcrypt';
// Set this as appropriate
const SALT_ROUNDS = 10;

class User {
  async insert(doc) {
    // We don't want to store passwords plaintext!
    const { password, ...rest } = doc;
    const hash = await bcrypt.hash(password, SALT_ROUNDS);
    const docToInsert = Object.assign({}, rest, {
      hash,
      createdAt: Date.now(),
      updatedAt: Date.now(),
    });

    // This code is unchanged.
    const id = (await this.collection.insertOne(docToInsert)).insertedId;
    this.pubsub.publish('userInserted', await this.findOneById(id));
    return id;
  }
}

Client side code

To create users, simply call your generated createUser mutation (you may want to add authorization to the resolver, feel free to modify it).

To login on the client, you make a RESTful request to /login on the server, passing email and password in JSON. You'll get a JWT token back, which you should attach to the Authorization header of all GraphQL requests.

Here's some code to do just that:

const KEY = 'authToken';
let token = localStorage.getItem(KEY);

const networkInterface = createNetworkInterface(/* as usual */);
networkInterface.use([
  {
    applyMiddleware(req, next) {
      req.options.headers = {
        authorization: token ? `JWT ${token}` : null,
        ...req.options.headers,
      };
      next();
    },
  },
]);

// Create your client as usual and pass to a provider
const client = /*...*/

// Call this function from your login form, or wherever.
const login = async function(serverUrl, email, password) {
  const response = await fetch(`${serverUrl}/login`, {
    method: 'POST',
    body: JSON.stringify({ email, password }),
    headers: { 'Content-Type': 'application/json' },
  });
  const data = await response.json();
  token = data.token;
  localStorage.setItem(KEY, token);
}

Development

Running code generation tests

You can run some basic code generation tests with npm test.

Testing full app code generation

A simple test to check that using the test/input input files with the CGS scripts generates test/output-app can be run with npm run output-app-generation-test.

Running end-to-end tests

You can run a set of end-to-end tests of the user/tweet app (which lives in test/output-app) with npm run end-to-end-test. This will seed the database, and run against a running server.

The test files are in test/output-app-end-to-end.

You need to start the standard server with cd test/output-app; npm start, then run npm run end-to-end-test.

Creating seed database

If you need to change the fixtures for the test db

Start the server, then run

mongoexport --host 127.0.0.1:3002 --db database --collection user > seeds/User.json
mongoexport --host 127.0.0.1:3002 --db database --collection tweet > seeds/Tweet.json

Maintenance

As this is a code generator, and not a library, once you run the code, you are on your own :)

By which I mean, you should feel free to read the generated code, understand it, and modify it as you see fit. Any updates to CGS will just affect future apps that you generate.

If you'd like to see improvements, or find any bugs, by all means report them via the issues, and send PRs. But workarounds should be always be possible simply by patching the generated code.

More Repositories

1

meteor-router

JavaScript
366
star
2

meteor-paginated-subscription

JavaScript
64
star
3

meteor-cron

JavaScript
49
star
4

meteor-presence

JavaScript
44
star
5

meteor-transitioner

JavaScript
42
star
6

iron-transitioner

JavaScript
36
star
7

transition-helper

JavaScript
31
star
8

multi-app-accounts

JavaScript
28
star
9

meteor-models

JavaScript
25
star
10

meteor-accounts-anonymous

JavaScript
17
star
11

meteor-gravatar

JavaScript
13
star
12

ruby-ddp-client

Ruby
10
star
13

tasklist-demo

CSS
9
star
14

meteor-page-js

A straightforward wrapper around the excellent page.js.
JavaScript
7
star
15

meteor-HTML5-History-API

JavaScript
7
star
16

premailer-rails

A plugin to hook premailer into ActionMailer
Ruby
7
star
17

meteor-recorder

JavaScript
6
star
18

meteor-errors

JavaScript
5
star
19

edifice

Ruby
5
star
20

meteor-deps-extensions

JavaScript
4
star
21

tasklist-demo-server

JavaScript
4
star
22

meteor_nowrite

JavaScript
3
star
23

storybook-skeleton

JavaScript
3
star
24

react-leaderboard

JavaScript
3
star
25

spectral-clustering

Code for the paper Spectral Clustering with Inconsistent Advice
MATLAB
3
star
26

prototyping-with-meteor

JavaScript
3
star
27

yacwi

Yet Another Calendar Web Interface
Java
3
star
28

meteor-crypto-md5

JavaScript
3
star
29

acceptance-test-driver

JavaScript
3
star
30

meteor-svg

Experiments with svg and meteor
JavaScript
2
star
31

edifice-forms

Unobtrusive JS Form Extensions for rails 3.1
Ruby
2
star
32

css_timings

A little test framework to run CSS timing tests.
Ruby
2
star
33

meteor-page-js-ie-support

JavaScript
2
star
34

react-form

JavaScript
2
star
35

sketch

CoffeeScript
2
star
36

mongo-find-by-ids

Find a list of mongo documents from a list of ids
JavaScript
2
star
37

meteor-experiments

A series of small test apps to do performance experiments on
JavaScript
2
star
38

meteor-static

Simple python script to make a static bundle from a Meteor project
Python
1
star
39

tmeasday.github.com

Personal OS Website for Tom Coleman
HTML
1
star
40

league-mailer

Ruby
1
star
41

cursor-utils

JavaScript
1
star
42

helpers_vs_partials

A project testing the performance of helpers vs partials
Ruby
1
star
43

meteor-double-publication-remove-bug

JavaScript
1
star
44

uihooks-removed-element

JavaScript
1
star
45

test-smart-package

A smart package with a smart.json
JavaScript
1
star
46

meteor-location

JavaScript
1
star
47

react-todos

JavaScript
1
star
48

test-app-feb-13

JavaScript
1
star
49

mitreskiclub.com

1
star
50

simple-meteor-chromatic-app

JavaScript
1
star
51

storybook-708

JavaScript
1
star
52

video_tools

Tools for converting videos on OS X
Ruby
1
star
53

url_hash

Create url-embeddable hashes from integers
Ruby
1
star
54

astrograph

JavaScript
1
star
55

edifice-widgets

Widgets + Traits done the edifice way
Ruby
1
star
56

meteor-storybook-experiment

1
star
57

test

1
star
58

timeoutapp

JavaScript
1
star
59

cordova-demo

JavaScript
1
star
60

noodletools_mock

Ruby
1
star
61

sass_rails_slowness

A demonstration of the difference in compilation time between command line sass and rails sass
Ruby
1
star
62

shareabouts

JavaScript
1
star
63

iron-scroll

JavaScript
1
star
64

meteor-talk

JavaScript
1
star
65

meteor.com-mongo-backup

Python
1
star
66

meteor-trello-example

JavaScript
1
star
67

amble-clean

A clean rails 2.3 project with bits of amble
Ruby
1
star
68

percolate

the public facing website of percolatestudio.com
Ruby
1
star
69

bikespot

JavaScript
1
star