Merge branch 'feature/docs'

This commit is contained in:
Adrian Obelmejias
2016-03-05 00:06:49 -05:00
11 changed files with 249 additions and 14 deletions
+2 -1
View File
@@ -8,7 +8,8 @@
"semi": [2, "never"],
"no-param-reassign": [2, { "props": false }],
"strict": 0,
"comma-dangle": [2, "never"]
"comma-dangle": [2, "never"],
"max-len": [2, 80, 2, { "ignoreComments": true }]
},
"env": {
"node": true,
+3
View File
@@ -53,3 +53,6 @@ node_modules
# sftp configuration file
sftp-config.json
#Documentation
docs
+18 -5
View File
@@ -2,10 +2,10 @@
Boilerplate for building APIs with [koa2](https://github.com/koajs/koa/tree/v2.x) and mongodb.
This project covers basic necessities of most APIs.
* Authentication (passport & jwt)
* Database (mongoose)
* Testing (mocha)
* Doc generation with jsondoc
##Requirements
* node __^4.0.0__
@@ -17,7 +17,7 @@ git clone https://github.com/adrianObel/koa2-api-boilerplate.git
```
##Features
* [Koa](https://github.com/koajs/koa/tree/v2.x)
* [koa2](https://github.com/koajs/koa/tree/v2.x)
* [koa-router](https://github.com/alexmingoia/koa-router)
* [koa-bodyparser](https://github.com/koajs/bodyparser)
* [koa-generic-session](https://github.com/koajs/generic-session)
@@ -27,14 +27,21 @@ git clone https://github.com/adrianObel/koa2-api-boilerplate.git
* [Passport](http://passportjs.org/)
* [Nodemon](http://nodemon.io/)
* [Mocha](https://mochajs.org/)
* [jsondoc](http://apidocjs.com/)
* [Babel](https://github.com/babel/babel)
* [ESLint](https://esling.ord)
* [ESLint](http://eslint.org/)
##Structure
```
├── bin
│ └── server.js # Bootstrapping and entry point
├── config # Server configuration settings
│ ├── server.js # Bootstrapping and entry point
│ ├── config.js # JSON dictionary for environment specific config
│ ├── env # Environment specific config
│ ├── common.js
│ │ ├── development.js
│ │ ├── production.js
│ │ └── test.js
│ ├── index.js # Config entrypoint - exports config according to envionrment and commons
│ └── passport.js # Passportjs config of strategies
├── src # Source code
│ ├── controllers # Routes
@@ -47,7 +54,13 @@ git clone https://github.com/adrianObel/koa2-api-boilerplate.git
##Usage
* `npm start` Start server on live mode
* `npm run dev` Start server on dev mode with nodemon
* `npm run docs` Generate API documentation
* `npm test` Run mocha tests
##Documentation
API documentation is written inline and generated by [jsondoc](http://apidocjs.com/).
Visit `http://localhost:5000/docs/` to view docs
##License
MIT
+6 -2
View File
@@ -5,8 +5,10 @@ import logger from 'koa-logger'
import mongoose from 'mongoose'
import session from 'koa-generic-session'
import passport from 'koa-passport'
import mount from 'koa-mount'
import serve from 'koa-static'
import config from './config'
import config from '../config'
import { errorMiddleware } from '../src/middleware'
const app = new Koa()
@@ -19,7 +21,9 @@ app.use(convert(bodyParser()))
app.use(convert(session()))
app.use(errorMiddleware())
require('./passport')
app.use(convert(mount('/docs', serve(`${process.cwd()}/docs`))))
require('../config/passport')
app.use(passport.initialize())
app.use(passport.session())
+1 -1
View File
@@ -1,3 +1,3 @@
require("babel-core/register")();
require("babel-polyfill");
require('./config/server.js');
require('./bin/server.js');
+13 -1
View File
@@ -7,7 +7,8 @@
"start": "node index.js",
"dev": "./node_modules/.bin/nodemon index.js",
"test": "NODE_ENV=test ./node_modules/.bin/mocha --compilers js:babel-register --require babel-polyfill",
"lint": "eslint src/**/*.js"
"lint": "eslint src/**/*.js",
"docs": "./node_modules/.bin/apidoc -i src/ -o docs"
},
"keywords": [
"koa2-api-boilerplate",
@@ -21,6 +22,14 @@
],
"author": "Adrian Obelmejias <adrian@obel.me>",
"license": "MIT",
"apidoc": {
"title": "koa2-api-boilerplate",
"url": "localhost:5000"
},
"repository": {
"type": "git",
"url": "https://github.com/adrianObel/koa2-api-boilerplate"
},
"dependencies": {
"babel-core": "^6.5.1",
"babel-polyfill": "^6.5.0",
@@ -34,12 +43,15 @@
"koa-convert": "^1.2.0",
"koa-generic-session": "^1.10.1",
"koa-logger": "^1.3.0",
"koa-mount": "^1.3.0",
"koa-passport": "^2.0.1",
"koa-router": "^7.0.1",
"koa-static": "^2.0.0",
"mongoose": "^4.4.3",
"passport-local": "^1.0.0"
},
"devDependencies": {
"apidoc": "^0.15.1",
"babel-eslint": "^4.1.8",
"babel-register": "^6.5.1",
"chai": "^3.5.0",
+51 -1
View File
@@ -1,10 +1,60 @@
import Router from 'koa-router'
import passport from 'koa-passport'
import jwt from 'jsonwebtoken'
import config from '../../config/config'
import config from '../../config'
const router = new Router({ prefix: '/auth' })
/**
* @apiDefine TokenError
* @apiError Unauthorized Invalid JWT token
*
* @apiErrorExample {json} Unauthorized-Error:
* HTTP/1.1 401 Unauthorized
* {
* "status": 401,
* "error": "Unauthorized"
* }
*/
/**
* @api {post} /auth Authenticate user
* @apiVersion 1.0.0
* @apiName AuthUser
* @apiGroup Auth
*
* @apiParam {String} username User username.
* @apiParam {String} password User password.
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X POST -d '{ "username": "johndoe@gmail.com", "password": "foo" }' localhost:5000/auth
*
* @apiSuccess {Object} user User object
* @apiSuccess {ObjectId} user._id User id
* @apiSuccess {String} user.name User name
* @apiSuccess {String} user.username User username
* @apiSuccess {String} token Encoded JWT
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "user": {
* "_id": "56bd1da600a526986cf65c80"
* "username": "foo"
* "username": "johndoe"
* },
* "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ"
* }
*
* @apiError Unauthorized Incorrect credentials
*
* @apiErrorExample {json} Error-Response:
* HTTP/1.1 401 Unauthorized
* {
* "status": 401,
* "error": "Unauthorized"
* }
*/
router.post('/', async (ctx, next) =>
passport.authenticate('local', (user) => {
if (!user) {
+153 -1
View File
@@ -1,11 +1,38 @@
import Router from 'koa-router'
import User from '../models/users'
import config from '../../config/config'
import config from '../../config'
import jwt from 'jsonwebtoken'
import { ensureUser } from '../middleware/validators'
const router = new Router({ prefix: '/users' })
/**
* @api {get} /users Get all users
* @apiPermission user
* @apiVersion 1.0.0
* @apiName GetUsers
* @apiGroup Users
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X GET localhost:5000/users
*
* @apiSuccess {Object[]} users Array of user objects
* @apiSuccess {ObjectId} users._id User id
* @apiSuccess {String} users.name User name
* @apiSuccess {String} users.username User username
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "users": [{
* "_id": "56bd1da600a526986cf65c80"
* "name": "John Doe"
* "username": "johndoe"
* }]
* }
*
* @apiUse TokenError
*/
router.get('/',
ensureUser,
async (ctx) => {
@@ -14,6 +41,33 @@ router.get('/',
}
)
/**
* @api {get} /users/:id Get user by id
* @apiPermission user
* @apiVersion 1.0.0
* @apiName GetUser
* @apiGroup Users
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X GET localhost:5000/users/56bd1da600a526986cf65c80
*
* @apiSuccess {Object} users User object
* @apiSuccess {ObjectId} users._id User id
* @apiSuccess {String} users.name User name
* @apiSuccess {String} users.username User username
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "user": {
* "_id": "56bd1da600a526986cf65c80"
* "name": "John Doe"
* "username": "johndoe"
* }
* }
*
* @apiUse TokenError
*/
router.get('/:id',
ensureUser,
async (ctx) => {
@@ -34,6 +88,44 @@ router.get('/:id',
}
)
/**
* @api {post} /users Create a new user
* @apiPermission
* @apiVersion 1.0.0
* @apiName CreateUser
* @apiGroup Users
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X POST -d '{ "user": { "username": "johndoe", "password": "secretpasas" } }' localhost:5000/users
*
* @apiParam {Object} user User object (required)
* @apiParam {String} user.username Username.
* @apiParam {String} user.password Password.
*
* @apiSuccess {Object} users User object
* @apiSuccess {ObjectId} users._id User id
* @apiSuccess {String} users.name User name
* @apiSuccess {String} users.username User username
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "user": {
* "_id": "56bd1da600a526986cf65c80"
* "name": "John Doe"
* "username": "johndoe"
* }
* }
*
* @apiError UnprocessableEntity Missing required parameters
*
* @apiErrorExample {json} Error-Response:
* HTTP/1.1 422 Unprocessable Entity
* {
* "status": 422,
* "error": "Unprocessable Entity"
* }
*/
router.post('/',
async (ctx) => {
const user = new User(ctx.request.body.user)
@@ -56,6 +148,46 @@ router.post('/',
}
)
/**
* @api {put} /users/:id Update a user
* @apiPermission
* @apiVersion 1.0.0
* @apiName UpdateUser
* @apiGroup Users
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X PUT -d '{ "user": { "name": "Cool new Name" } }' localhost:5000/users/56bd1da600a526986cf65c80
*
* @apiParam {Object} user User object (required)
* @apiParam {String} user.name Name.
* @apiParam {String} user.username Username.
*
* @apiSuccess {Object} users User object
* @apiSuccess {ObjectId} users._id User id
* @apiSuccess {String} users.name Updated name
* @apiSuccess {String} users.username Updated username
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "user": {
* "_id": "56bd1da600a526986cf65c80"
* "name": "Cool new name"
* "username": "johndoe"
* }
* }
*
* @apiError UnprocessableEntity Missing required parameters
*
* @apiErrorExample {json} Error-Response:
* HTTP/1.1 422 Unprocessable Entity
* {
* "status": 422,
* "error": "Unprocessable Entity"
* }
*
* @apiUse TokenError
*/
router.put('/:id',
ensureUser,
async (ctx) => {
@@ -81,6 +213,26 @@ router.put('/:id',
}
)
/**
* @api {delete} /users/:id Delete a user
* @apiPermission
* @apiVersion 1.0.0
* @apiName DeleteUser
* @apiGroup Users
*
* @apiExample Example usage:
* curl -H "Content-Type: application/json" -X DELETE localhost:5000/users/56bd1da600a526986cf65c80
*
* @apiSuccess {StatusCode} 200
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "status": 200
* }
*
* @apiUse TokenError
*/
router.delete('/:id',
ensureUser,
async (ctx) => {
+1 -1
View File
@@ -1,5 +1,5 @@
import User from '../models/users'
import config from '../../config/config'
import config from '../../config'
import { verify } from 'jsonwebtoken'
export async function ensureUser(ctx, next) {
+1 -1
View File
@@ -1,4 +1,4 @@
import app from '../config/server'
import app from '../bin/server'
import supertest from 'supertest'
import { expect, should } from 'chai'
import { cleanDb } from './utils'