cd2bit / signsfive-api

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

documentation/images/signsfive-announcement-facebook_1200x630.jpg

SignsFive API

https://travis-ci.org/deafchi/signsfive-api.svg?branch=master

Development with Docker Quick Start

During development, there are 3 key files:

  • .env.sample
  • docker-compose.yml
  • docker-compose.dev.yml

First, you need to copy .env.sample to .env and make any edits if needed in your newly copied .env file.

Next, both docker-compose.yml and docker-compose.dev.yml are required, so they are combined by running command provided by scripts in package.json:

npm run dev

NOTE: This might take signsfive_api to restart couple of time due to race condition with database starting up. See: /issues/26

Quick Start (Non-Docker)

nvm use
npm install
npm start

Logging with Bunyan

Bunyan is used for all of our logging purposes. We create a single instance from which all children are born in logger.js.

Logging in the Code

Restify provides a requestLogger plugin which extends the req.log object, so you can do:

server.get('/foo', function(req, res, next){
  req.log.info('bar');
  res.send({message: 'baz'});
});

which adds a request ID for each request made to the logged information, allowing all requests to be traced easily.

Human-Readable Logs

You can read the logs by piping through bunyan itself:

tail -f server.log | ./node_modules/bunyan/bin/bunyan

Testing

Tests can be run with:

npm test

which uses mocha, chai, and supertest to run all of the available tests. Travis-CI is used to

  • install packages and check dependencies,
  • run the mocha test suite,
  • and deploy to heroku

Documentation

Code Structure

  • .sequelizerc contains configuration for the sequelize cli
  • config/ contains configuration files for database and other services
  • db/ contains database model, seeder, and migration files
  • index.js is our server entrypoint
  • package.json is self-explanatory
  • scripts/ contains various scripts, such as those referenced by package.json
  • services/ contains code that runs various services as singletons, the exception being sequelize which is in db/
  • test/ contains our tests
  • utils.js contains some utility functions we like

Database Schema Diagram

see details

Database Management

See sequelize tutorial for in-depth details. Setting up the structure for the first time with the sequelize cli is as easy as running:

node_modules/.bin/sequelize init

To view all possible commands, run:

node_modules/.bin/sequelize

Models and Migrations

To create a model, you can use the model:generate command:

node_modules/.bin/sequelize model:generate --name User --attributes firstName:string,lastName:string,email:string

which creates a User model in db/models/ folder and a migration file with name like XYZ-create-user.js in db/migrations/ folder. You can then run this migration:

node_modules/.bin/sequelize db:migrate

to create this new user table. Similarly, you can undo this migration with:

node_modules/.bin/sequelize db:migrate:undo

or to undo all:

node_modules/.bin/sequelize db:migrate:undo:all

or to a specific migration:

node_modules/.bin/sequelize db:migrate:undo:all --to XYZ-create-user.js

Migration Procedure Example

Based on the way we've organized it, we are enforcing migrations for changes to our database in an atomic, consistent, testable way. To make sure this happens correctly, realize that migrations are for changing the database structure only. Client code such as validation and helper functions for existing database relationships (adding belongsToMany for example) is not part of a migration. That said, migrations will be done on a best-effort. As an example, let's say we would like to create a migration that adds a many-to-many relationship between gloss and sign models. That is, we would like belongsToMany in both directions of the relationship.

  1. Run:

    node_modules/.bin/sequelize model:generate --name gloss_sign --attributes glossId:integer,signId:integer
    
  2. Remove the generated model file under db/models/gloss_sign.js. We are not adding a new "model" per-se, but we are creating a new table. Technically, we should just create a migration, but it's easier to let this set up a lot of the default entries for us to make this connection work.

  3. Edit the migration file that was just created, make sure the table name is gloss_sign and not gloss_signs -- as sequelize tends to pluralize automatically.

  4. Continue editing by adding the following information on the foreign keys we plan to make:

    glossId: {
      primaryKey: true,
      allowNull: false,
      type: Sequelize.INTEGER,
      references: {model: 'glosses', key: 'id'},
      onUpdate: 'CASCADE',
      onDelete: 'CASCADE'
    },
    signId: {
      primaryKey: true,
      allowNull: false,
      type: Sequelize.INTEGER,
      references: {model: 'signs', key: 'id'},
      onUpdate: 'CASCADE',
      onDelete: 'CASCADE'
    },
    
  5. Next, edit by removing the id column from the table. Since we are using a compound primary key of (glossId, signId) and will automatically cascade updates, we don't need to do any extra work to ensure that this is unique.

  6. Next, edit db/models/sign.js and db/models/gloss.js to add belongsToMany relationships. For example, in sign.js:

    sign.associate = models => {
      ...
      sign.belongsToMany(models.gloss, {as: "Glosses", through: "gloss_sign", foreignKey: "signId", otherKey: "glossId"});
      ...
    };
    
  7. Finally, run a series of migrations to ensure that we can rewind and playback with no issues:

    node_modules/.bin/sequelize db:migrate
    node_modules/.bin/sequelize db:migrate:undo
    node_modules/.bin/sequelize db:migrate
    

and that's it. You've created a many-to-many relationship with migrations! Note that the migration's job here was just to create the tables according to the kind of relationship we were adding (belongsToMany) and we configured the belongsToMany call based exactly on the table we created (gloss_sign) and the foreign keys in that table (signId, glossId).

For more information, see the following blog posts:

Database Setup

To set up the dev environment locally for MySQL, I just ran brew install mysql to install it, then:

$ mysql.server start
$ mysql -u root
mysql> GRANT ALL PRIVILEGES ON signsfive_dev.* TO 'signsfive_dev'@'localhost' IDENTIFIED BY 'signsfive_dev';

to create a signsfive_dev user with the same password and full access to the database of the same name.

About


Languages

Language:JavaScript 100.0%