Name: base-api-nodejs
Owner: Topcoder
Description: A base server to use a swagger based API using a127
Created: 2014-10-14 12:46:49.0
Updated: 2017-10-17 19:47:48.0
Pushed: 2015-02-12 15:46:55.0
Homepage: null
Size: 220
Language: JavaScript
GitHub Committers
User | Most Recent Commit | # Commits |
---|
Other Committers
User | Most Recent Commit | # Commits |
---|
This is a walk through of building a nodeJS micro service using the serenely modules. We will implement the petstore example from wordnik (http://petstore.swagger.wordnik.com/). This is the example which is used to demonstrate a swagger specificaiton.
Swagger Spec: https://github.com/swagger-api/swagger-spec/blob/master/examples/v2.0/yaml/petstore-expanded.yaml
Each step will be a new git tag with new instructions in this file.
This is the base repository with the boilerplate code to get your started. It contains the following files.
Swagger is used to built out the routes and API documentation. We take a Documentation first approach to building API's.
We will be using the modified version of the swagger file from https://github.com/swagger-api/swagger-spec/blob/master/examples/v2.0/yaml/petstore-expanded.yaml. The differences being in removing the “allOf” which is not supported and adding a few a127 specific elements. The a127 elements will be described when we use them.
api/swagger/swagger.yaml
node app.js
http://localhost:10010/docs
At this point you should have a working Swagger UI. We don't have any functional API's yet but you have the beginnings on one.
Like any good application developer, we will follow TDD (Test Driven Development) and create our tests.
Included in the code base is mocha, should and supertest to help you write your tests. The tests included are very limited and should be expanded to include the /pets quering and error responses.
Before we can run the tests, we will need to setup our database.
petstore
postgres://postgres@localhost:5432/petstore
At this point you should be able test with all of them failing.
Since we have a fully documented API in teh swagger.yaml file, we can pull out the implied database schema.
Looking at the definitions section we see the following:
Pet:
required:
- id
- name
properties:
id:
type: integer
format: int64
name:
type: string
tag:
type: string
This translates to the following in postgres.
TE TABLE pets
integer NOT NULL,
me character varying,
g text,
NSTRAINT pets_pkey PRIMARY KEY (id)
Let's add this to our schema migration.
grunt migrate:create:add-pets
to generate the migration file.rts.up = function (db, callback) {
.createTable('pets', {
id: { type: 'int', primaryKey: true },
name: 'string',
tag: 'text'
callback);
rts.down = function (db, callback) {
.dropTable('pets', callback);
grunt dbmigrate
to create the table.Now you have a working database migration stored in a file which will be easy to deploy.
Now let's define our models to match our database schema. We use Sequlize as our ORM to connect to PostgreSQL. The connection it bootstrapped via the datasource.js file and the serenity-datasource npm module. The models are imported using the Sequelize.import command
Our models expect a function where the sequlize object is the first argument and the DataTypes are the second.
api/models
create a file called pet.js
epresent a Pet.
strict';
fining Challenge model
le.exports = function(sequelize, DataTypes) {
r Pet = sequelize.define('Pet', {
// primary key
id: {
type: DataTypes.BIGINT, primaryKey: true, autoIncrement: true,
get: function() {
return parseInt(this.getDataValue('id'));
}
},
name: DataTypes.STRING(140)
;
turn Pet;
We defined the model to match the database schema and the structure of the swagger yaml Pet definition.
Creating the controllers are very easy using the serenity-controller-helper module. The controller helper builds out common functionality for controllers. We can create the controller needed for to access the Pet data with only 14 lines of code:
strict';
datasource = require('./../../datasource').getDataSource();
Pet = datasource.Pet;
serenityControllerHelper = require('serenity-controller-helper');
config = require('config');
controllerHelper = new serenityControllerHelper(config);
uild controller
petController = controllerHelper.buildController(Pet, [], {filtering: true});
le.exports = {
ndPets: petController.all,
dPet: petController.create,
ndPetById: petController.get,
datePet: petController.update,
letePet: petController.delete
In the app.js file we wire up all of the middlewares.
Wire up the database.
tasource.init(config);
Allow the use of the Google Partial Respone Pattern to access related Data. See below for examples.
rtialResponseHelper = new ResponseHelper(datasource);
p.use(partialResponseHelper.parseFields);
Go a127 Go!
p.use(a127.middleware(swaggerConfig));
Display the swagger documentation UI
Serve the Swagger documents and Swagger UI
(config.has('app.loadDoc') && config.get('app.loadDoc')) {
// adding ui options
var swaggerTools = swaggerConfig['a127.magic'].swaggerTools;
app.use(swaggerTools.swaggerUi({
swaggerUi: config.ui.swaggerUi,
apiDocs: config.ui.apiDocs
}));
Add an error handing
Add logging
p.use(function(err, req, res, next) {
if (err) {
winston.error(err.stack || JSON.stringify(err));
routeHelper.middleware.errorHandler(err, req, res, next);
} else {
next();
}
;
Respond with JSON
render response data as JSON
p.use(routeHelper.middleware.renderJson);
GO SERVER GO!
p.listen(port);