Skip to content

Instantly share code, notes, and snippets.

@khaosdoctor
Last active July 9, 2017 01:46
Show Gist options
  • Save khaosdoctor/1c04a71a60b72bed7797585a04a0d351 to your computer and use it in GitHub Desktop.
Save khaosdoctor/1c04a71a60b72bed7797585a04a0d351 to your computer and use it in GitHub Desktop.
Example script for medium article
const logger = require('knoblr')
const mongoose = require('mongoose')
const Koa = require('koa')
const jwt = require('koa-jwt')
const parser = require('koa-body')()
const cors = require('../shared/configs/cors')
const ServerException = require('../shared/errors/ServerException')
/**
* Realiza a conexão no banco de dados
*
* @returns {Promise} Conexão do mongoose
* @inner
* @private
* @func connect
*/
function connect () { // Conecta no Database e inicia o servidor Koa
mongoose.Promise = global.Promise // Substitui a lib de promises do mongo (obrigatório)
const mongoOptions = { // Habilita o keepalive para não fazer as conexões com o mongo em todas as chamadas
useMongoClient: true,
server: {
socketOptions: {
keepAlive: 120
}
},
replSet: {
socketOptions: {
keepAlive: 120
}
}
}
return mongoose.connect(process.env.MONGODB_URI + process.env.MONGODB_NAME, mongoOptions) // Temos estas variáveis por causa do arquivo .env que foi carregado no index.js
}
/**
* Instancia um novo servidor do Koa
*
* @returns {Koa} Servidor do Koa
* @inner
* @private
* @func createServer
*/
function createServer () { // Cria um servidor novo do Koa
logger.info(`Mongo conectado`)
const server = new Koa()
// O Koa trabalha com eventos, pois retorna uma instancia do HTTPClient do Node, então temos que ouvir estes eventos
server.on('error', (err, ctx) => { // Ouve o evento de erro
logger.error(`Server Error: ${err}`)
ctx.status = 500
})
return server
}
/**
* Seta o servidor com os middlewares
*
* @param {Koa} server Servidor do Koa
* @returns {Koa} Servidor do koa com middlewares
* @inner
* @private
* @func setupMiddlewares
*/
function setupMiddlewares (server) { // Note que estamos trazendo o Server da função anterior como parâmetro
server.use(cors()) // Precisamos utilizar o CORS (Cross Origin Resource Sharing) para poder acessar externamente quando em produção
server.use((ctx, next) => { // Se o token não for válido retorna 401
return next().catch((err) => { // Executa o próximo middleware, que é o JWT, se falhar o usuário é inválido
if (err.status === 401) {
logger.warn(`Acesso não autorizado de ${ctx.host} a rota ${ctx.url}`)
ctx.status = 401
ctx.body = 'Unauthorized'
} else {
throw err
}
})
})
server.use(parser) // Parseia o body das requisições com payload (PUT, POST, PATCH)
return server
}
/**
* Seta o uso do middleware de JWT
*
* @param {Koa} server Servidor Koa
* @returns {Koa} Servidor koa
* @inner
* @private
* @func setupAuth
*/
function setupAuth (server) {
server.use(jwt({ // Usa o middleware de JWT com as credenciais necessárias para decodificar o mesmo
secret: new Buffer(process.env.CLIENT_SECRET, 'base64'),
audience: process.env.CLIENT_ID
})
.unless({ path: [/^\/status/] })) // A Não ser que a rota seja de status, ai não precisa de segurança porque ela é pública
return server
}
/**
* Registra todas as rotas no Koa
* @func registerRoutes
* @inner
* @private
*/
function registerRoutes (server) {
const routes = require('glob') // Busca os arquivos de rotas
.sync(require('path')
.join(__dirname, './routes/**/*.js')) // Obtém todos os nomes de arquivos da pasta routes que terminam em '.js'
routes.forEach(route => { // Para cada rota
server.use(require(route).route) // Registra ela no servidor Koa
logger.info(`Rota ${route.split('/').pop().split('.').shift()} registrada`) // Informa o sysadmin através de um log
})
return server
}
/**
* Inicia o listener do server
*
* @param {Koa} server Servidor Koa
* @returns void
* @inner
* @private
* @func startServer
*/
function startServer (server) {
return server.listen(process.env.PORT, () => { // Inicia o servidor
logger.info(`Alfred pronto na porta ${process.env.PORT}`)
})
}
// Chama todas as funções em ordem e retorna um unico objeto pronto para uso
const alfred = () => connect() // Objeto final instanciado da API
.then(createServer)
.then(setupMiddlewares)
.then(setupAuth)
.then(registerRoutes)
.then(startServer)
.catch((error) => { // Erro de conexão
logger.error(`Erro de conexão de banco de dados => ${error}`)
throw new ServerException(error, null)
})
module.exports = alfred
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment