-
Notifications
You must be signed in to change notification settings - Fork 3
NodeJS starter setup. #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
7b8f0ea
7d22fbb
cac594c
d6febc9
eb71aa6
3f5c4d0
49d37e4
3d80d77
a1ce2e0
ec3668c
ae88dac
8f313f0
6f9b0e8
7ec80a9
5a0a2e3
e167c6c
d92508c
6a46a5d
2566319
a459ca8
1b9a6b2
4dc44ec
27c155a
abf5472
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,4 @@ | ||
| tabWidth: 2 | ||
| printWidth: 120 | ||
| singleQuote: true | ||
| arrowParens: avoid |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,7 @@ | ||
| { | ||
| "name": "express-api-es6-starter", | ||
| "name": "@leapfrogtechnology/nodejs-starter", | ||
| "version": "1.0.0", | ||
| "description": "Express API ES6 Starter", | ||
| "description": "NodeJS Starter", | ||
| "scripts": { | ||
| "start": "node dist", | ||
| "prestart": "yarn build", | ||
|
|
@@ -47,10 +47,10 @@ | |
| "dependencies": { | ||
| "@hapi/boom": "^9.1.0", | ||
| "@hapi/joi": "^17.1.1", | ||
| "@leapfrogtechnology/async-store": "^1.2.0", | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👌 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Feel free to do a PR / issue if there are anything for it. |
||
| "@sentry/node": "^5.15.0", | ||
| "axios": "^0.19.2", | ||
| "body-parser": "^1.19.0", | ||
| "bookshelf": "^1.1.0", | ||
| "bookshelf-virtuals-plugin": "^0.1.1", | ||
| "compression": "^1.7.4", | ||
| "cors": "^2.8.5", | ||
| "dotenv": "^8.2.0", | ||
|
|
@@ -60,7 +60,7 @@ | |
| "knex": "^0.20.12", | ||
| "lodash": "^4.17.13", | ||
| "morgan": "^1.10.0", | ||
| "pg": "^7.18.2", | ||
| "mysql": "^2.18.1", | ||
| "serve-favicon": "^2.5.0", | ||
| "swagger-jsdoc": "^3.5.0", | ||
| "swagger-ui-dist": "^3.25.0", | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,70 @@ | ||||||||||||||
| import * as store from '@leapfrogtechnology/async-store'; | ||||||||||||||
|
|
||||||||||||||
| import { http } from '../utils/http'; | ||||||||||||||
| import TokenError from '../errors/token'; | ||||||||||||||
|
|
||||||||||||||
| /** | ||||||||||||||
| * Extract token from headers in http request. | ||||||||||||||
| * | ||||||||||||||
kabirbaidhya marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
| * @param {Object} headers | ||||||||||||||
| * @returns {Object} | ||||||||||||||
| */ | ||||||||||||||
| function extractTokenFromHeaders(headers = {}) { | ||||||||||||||
| const { authorization = '' } = headers; | ||||||||||||||
|
|
||||||||||||||
| const [tokenType, token] = authorization.split(' ').filter(Boolean); | ||||||||||||||
|
|
||||||||||||||
| if (tokenType !== 'Bearer' || !token) { | ||||||||||||||
| return { | ||||||||||||||
| ok: false, | ||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Some There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Make it straight. Either return null to signify empty value or throw an error to state the failure -- nothing in between. |
||||||||||||||
| }; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| return { | ||||||||||||||
| token, | ||||||||||||||
| }; | ||||||||||||||
|
Comment on lines
+17
to
+25
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why different results in between cases? I think it could only be - token or null OR token or error.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Generally, user of the API when we tend to return OR OR all of which are optional if user choose not to handle the error properly. Agreed that return signature and method is a bit verbose here, however i think it forces dev to handle error explicitly. Allows dev to treat error as just another value. Any thoughts? This is not the typical JS standard way of error handling however languages like |
||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| /** | ||||||||||||||
| * Fetch user from auth server using token. | ||||||||||||||
| * | ||||||||||||||
| * @param {String} token | ||||||||||||||
| * @throws {NetworkError} | ||||||||||||||
| * @returns {Promise} | ||||||||||||||
| */ | ||||||||||||||
| async function fetchUserByToken(token) { | ||||||||||||||
| const { data } = await http.get(`${process.env.AUTH_URL}/userinfo`, { | ||||||||||||||
| headers: { | ||||||||||||||
| accessToken: token, | ||||||||||||||
| clientId: process.env.AUTH_CLIENT_ID, | ||||||||||||||
| }, | ||||||||||||||
| }); | ||||||||||||||
|
|
||||||||||||||
| return data; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| /** | ||||||||||||||
| * Validate token received in header. | ||||||||||||||
| * | ||||||||||||||
| * @param {Object} req | ||||||||||||||
| * @param {Object} res | ||||||||||||||
| * @param {Object} next | ||||||||||||||
| */ | ||||||||||||||
| async function authenticateUser(req, res, next) { | ||||||||||||||
| try { | ||||||||||||||
| const { ok, token } = extractTokenFromHeaders(req.headers); | ||||||||||||||
|
|
||||||||||||||
| if (!ok) { | ||||||||||||||
|
Comment on lines
+55
to
+57
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Couldn't be more simple than this.
Suggested change
|
||||||||||||||
| throw new TokenError('Invalid token'); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| const user = await fetchUserByToken(token); | ||||||||||||||
|
|
||||||||||||||
| store.set(user); | ||||||||||||||
| next(); | ||||||||||||||
| } catch (err) { | ||||||||||||||
| next(err); | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| export default authenticateUser; | ||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| import HttpStatus from 'http-status-codes'; | ||
|
|
||
| import * as userService from '../services/user'; | ||
|
|
||
| /** | ||
| * Get all users. | ||
| * | ||
| * @param {Object} req | ||
| * @param {Object} res | ||
| * @param {Function} next | ||
| */ | ||
| export async function fetch(req, res, next) { | ||
| try { | ||
| const data = await userService.fetch(); | ||
|
|
||
| res.json({ data }); | ||
| } catch (err) { | ||
| next(err); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Create a new user. | ||
| * | ||
| * @param {Object} req | ||
| * @param {Object} res | ||
| * @param {Function} next | ||
| */ | ||
| export async function create(req, res, next) { | ||
| try { | ||
| const data = await userService.create(); | ||
|
|
||
| res.status(HttpStatus.CREATED).json({ data }); | ||
| } catch (err) { | ||
| next(err); | ||
| } | ||
| } |
This file was deleted.
Uh oh!
There was an error while loading. Please reload this page.