Skip to content
This repository has been archived by the owner on Sep 27, 2022. It is now read-only.

Commit

Permalink
add ArticlesRoutes
Browse files Browse the repository at this point in the history
  • Loading branch information
guillaumemaka committed Jun 27, 2017
1 parent 487edb1 commit b48df2a
Show file tree
Hide file tree
Showing 39 changed files with 3,128 additions and 536 deletions.
3 changes: 0 additions & 3 deletions .eslintignore

This file was deleted.

7 changes: 4 additions & 3 deletions .labrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@

const internals = {
coverage: true,
threshold: 80,
threshold: 90,
colors: true,
timeout: 2000,
timeout: 10000,
verbose: true,
globals: 'Reflect,core,_babelPolyfill,regeneratorRuntime,__core-js_shared__'
}

internals.reporters = new Map([
['lcov', 'coverage/lcov.info'],
['console', 'stdout']
['console', 'stdout'],
['html', 'coverage/cov.html']
])

internals.reporter = Array.from(internals.reporters.keys())
Expand Down
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
# ![Node/Hapi.JS/Mongoose Example App](.github/project-logo.png)

[![Build Status](https://travis-ci.org/guillaumemaka/realworld-starter-kit-hapijs.svg?branch=master)](https://travis-ci.org/guillaumemaka/realworld-starter-kit-hapijs)
[![Code Climate](https://codeclimate.com/github/guillaumemaka/realworld-starter-kit-hapijs/badges/gpa.svg)](https://codeclimate.com/github/guillaumemaka/realworld-starter-kit-hapijs)
[![Test Coverage](https://codeclimate.com/github/guillaumemaka/realworld-starter-kit-hapijs/badges/coverage.svg)](https://codeclimate.com/github/guillaumemaka/realworld-starter-kit-hapijs/coverage)
[![Build Status](https://img.shields.io/travis/guillaumemaka/realworld-starter-kit-hapijs.svg?branch=master&style=flat-square)](https://travis-ci.org/guillaumemaka/realworld-starter-kit-hapijs)
[![Code Climate](https://img.shields.io/codeclimate/github/guillaumemaka/realworld-starter-kit-hapijs.svg?style=flat-square)](https://codeclimate.com/github/guillaumemaka/realworld-starter-kit-hapijs)
[![Code Climate Coverage](https://img.shields.io/codeclimate/coverage/github/guillaumemaka/realworld-starter-kit-hapijs.svg?style=flat-square)](https://codeclimate.com/github/guillaumemaka/realworld-starter-kit-hapijs/coverage)
[![Code Style](https://img.shields.io/badge/code_style-standard-brightgreen.svg?style=flat-square)](https://standardjs.com/)
[![Hapi.JS](https://img.shields.io/npm/v/hapi.svg?label=hapi&style=flat-square)](https://hapijs.com)
[![Mongoose](https://img.shields.io/npm/v/mongoose.svg?label=mongoose&style=flat-square)](http://mongoosejs.com/)

> ### Example Hapi.JS (Hapi.JS + Mongoose) codebase containing real world examples (CRUD, auth, advanced patterns, etc) that adheres to the [RealWorld](https://github.com/gothinkster/realworld-example-apps) API spec.
Expand Down
10 changes: 9 additions & 1 deletion lib/config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,15 @@ conf.auth = {
}

conf.database = {
uri: process.env.MONGO_DB_URI || 'mongodb://localhost:27017/conduit_' + process.env.NODE_ENV
uri: process.env.MONGO_DB_URI || 'mongodb://localhost:27017/conduit_' + process.env.NODE_ENV,
options: {
server: {
socketOptions: {
keepAlive: 300000,
connectTimeoutMS: 300000
}
}
}
}

module.exports = conf
5 changes: 5 additions & 0 deletions lib/config/manifest.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ const manifest = {
register: './models'
}
},
{
plugin: {
register: './services'
}
},
{
plugin: {
register: './api'
Expand Down
238 changes: 238 additions & 0 deletions lib/modules/api/articles/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
const inputValidations = require('./validations/input')
const outputValidations = require('./validations/output')
const replyHelper = require('../helpers')

const register = (server, options, next) => {
const fetchArticle = require('./routes_prerequisites').fetchArticle(server)
const fetchComment = require('./routes_prerequisites').fetchComment(server)
const authorizeArticle = require('./routes_prerequisites').authorizeArticle(server)
const authorizeComment = require('./routes_prerequisites').authorizeComment(server)

server.route([
// GET /api/articles
{
method: 'GET',
path: '/articles',
config: {
response: outputValidations.ListArticleOutputValidationsConfig,
validate: inputValidations.ArticlesQueryValidations
},
handler: (request, reply) => {
let user = request.auth.isAuthenticated ? request.auth.credentials.user : null
let query = request.query

server.methods.services.articles.list(user, query, (err, articles) => {
if (err) return reply(replyHelper.constructErrorResponse(err)).code(422)
return reply(articles)
})
}
},
// GET /api/articles/feed
{
method: 'GET',
path: '/articles/feed',
config: {
auth: 'jwt',
response: outputValidations.ListArticleOutputValidationsConfig,
validate: inputValidations.ArticlesQueryValidations
},
handler: (request, reply) => {
let user = request.auth.credentials.user
let query = request.query

server.methods.services.articles.feedFor(user, query, (err, articles) => {
if (err) return reply(replyHelper.constructErrorResponse(err)).code(422)
return reply(articles)
})
}
},
// POST /api/articles
{
method: 'POST',
path: '/articles',
config: {
auth: 'jwt',
response: outputValidations.SingleArticleOutputValidationsConfig,
validate: inputValidations.ArticleCreatePayloadValidations
},
handler: (request, reply) => {
server.methods.services.articles.create(
request.auth.credentials.user,
request.payload.article,
(err, article) => {
if (err) return reply(replyHelper.constructErrorResponse(err)).code(422)
return reply({ article: article.toJSONFor(request.auth.credentials.user) }).code(201)
})
}
},
// GET /api/articles/{slug}
{
method: 'GET',
path: '/articles/{slug}',
config: {
auth: { mode: 'try', strategy: 'jwt' },
pre: [
fetchArticle
],
response: outputValidations.SingleArticleOutputValidationsConfig,
validate: inputValidations.ArticleParamsValidations
},
handler: (request, reply) => {
var article = request.pre.article.toJSONFor(null)
if (request.auth.isAuthenticated) {
article = request.pre.article.toJSONFor(request.auth.credentials.user)
}
return reply({article})
}
},
// PUT /api/articles/{slug}
{
method: 'PUT',
path: '/articles/{slug}',
config: {
auth: 'jwt',
pre: [
fetchArticle,
authorizeArticle
],
response: outputValidations.SingleArticleOutputValidationsConfig,
validate: inputValidations.ArticleUpdatePayloadValidations
},
handler: (request, reply) => {
server.methods.services.articles.update(
request.pre.article,
request.payload.article,
(err, article) => {
if (err) return reply(replyHelper.constructErrorResponse(err)).code(422)
return reply({ article: article.toJSONFor(request.auth.credentials.user) })
})
}
},
// DELETE /api/articles/{slug}
{
method: 'DELETE',
path: '/articles/{slug}',
config: {
auth: 'jwt',
pre: [
fetchArticle,
authorizeArticle
],
response: outputValidations.SingleArticleOutputValidationsConfig,
validate: inputValidations.ArticleParamsValidations
},
handler: (request, reply) => {
server.methods.services.articles.delete(
request.pre.article,
(err, article) => {
if (err) return reply(replyHelper.constructErrorResponse(err)).code(422)
return reply().code(204)
})
}
},
// DELETE/POST /api/articles/{slug}/favorite
{
method: ['DELETE', 'POST'],
path: '/articles/{slug}/favorite',
config: {
auth: 'jwt',
pre: [
fetchArticle
],
response: outputValidations.SingleArticleOutputValidationsConfig,
validate: inputValidations.ArticleParamsValidations
},
handler: (request, reply) => {
var action = server.methods.services.users.favoriteArticle

if (request.method === 'delete') {
action = server.methods.services.users.unfavoriteArticle
}

action(
request.auth.credentials.user,
request.pre.article,
(err, article) => {
if (err) return reply(replyHelper.constructErrorResponse(err)).code(422)
return reply({article: article.toJSONFor(request.auth.credentials.user)})
})
}
},
// GET /api/articles/{slug}/comments
{
method: 'GET',
path: '/articles/{slug}/comments',
config: {
auth: { mode: 'try', strategy: 'jwt' },
pre: [
fetchArticle
],
response: outputValidations.ListCommentOutputValidationsConfig,
validate: inputValidations.ArticleParamsValidations
},
handler: (request, reply) => {
server.methods.services.comments.getCommentsFor(request.pre.article, (err, comments) => {
if (err) return reply(replyHelper.constructErrorResponse(err).code(422))
if (request.auth.isAuthenticated) {
return reply({ comments: comments.map(c => c.toJSONFor(request.auth.credentials.user)) })
}
return reply({ comments: comments.map(c => c.toJSONFor(null)) })
})
}
},
// POST /api/articles/{slug}/comments
{
method: 'POST',
path: '/articles/{slug}/comments',
config: {
auth: 'jwt',
pre: [
fetchArticle,
fetchComment
],
response: outputValidations.SingleCommentOutputValidationsConfig,
validate: inputValidations.CommentCreatePayloadValidations
},
handler: (request, reply) => {
server.methods.services.articles.addComment(
request.pre.article,
request.auth.credentials.user,
request.payload.comment,
(err, comment) => {
if (err) return reply(replyHelper.constructErrorResponse(err)).code(422)
return reply({ comment: comment.toJSONFor(request.auth.credentials.user) }).code(201)
})
}
},
// DELETE /api/articles/{slug}/comments/{commentId}
{
method: 'DELETE',
path: '/articles/{slug}/comments/{commentId}',
config: {
auth: 'jwt',
pre: [
fetchArticle,
fetchComment,
authorizeComment
],
validate: inputValidations.CommentParamsValidations
},
handler: (request, reply) => {
server.methods.services.articles.deleteComment(
request.pre.article,
request.pre.comment._id,
(err, _) => {
if (err) return reply(replyHelper.constructErrorResponse(err)).code(422)
return reply().code(204)
})
}
}
])
return next()
}

register.attributes = {
pkg: require('./package.json')
}

module.exports = register
4 changes: 4 additions & 0 deletions lib/modules/api/articles/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "articles",
"version": "1.0.0"
}
Loading

0 comments on commit b48df2a

Please sign in to comment.