danielfsousa / express-rest-boilerplate Goto Github PK
View Code? Open in Web Editor NEW⌛️ Express starter for building RESTful APIs
License: MIT License
⌛️ Express starter for building RESTful APIs
License: MIT License
Hey Daniel,
In , server/src/controllers/auth.controller.js
, it seems to me there's no check to see if the email exists already in the database.. (same check exists in user.controller.js)
/**
* Returns jwt token if registration was successful
* @public
*/
exports.register = async (req, res, next) => {
try {
const user = await (new User(req.body)).save(); // check here?
const userTransformed = user.transform();
const token = generateTokenResponse(user, user.token());
res.status(httpStatus.CREATED);
return res.json({ token, user: userTransformed });
} catch (error) {
return next(User.checkDuplicateEmail(error));
}
};
I am running a very similar implementation as your boilerplate and I get
POST http://localhost:3000/auth/register 409 (Conflict)
when I try to register with the same email.
I guess what I'd like to understand is the difference between auth.controller
and user.controller
(are they doing different tasks, are they complementary or are they two different options for authentication?)
Take a look at https://github.com/danielfsousa/monorepo-typescript-lib-starter for an example
Hello folks
I have tried to set up this as per guild but every time I am getting
error: MongoDB connection error: MongooseServerSelectionError: getaddrinfo ENOTFOUND mongodb
Even I tested with another project to check that Mongodb is working fine or not and it is working fine for another project.
this is the configuration I have
MongoDB version: 4.2.1
Mongoose: 5.6.7
node: 12.16.1
this is the mongoose connect method
exports.connect = () => { mongoose .connect(mongo.uri, { useCreateIndex: true, keepAlive: 1, useNewUrlParser: true, useUnifiedTopology: true, useFindAndModify: false, }) .then(() => console.log('mongoDB connected...')); return mongoose.connection; };
please help me what is the wrong I am doing.
Maybe Redis?
userSchema.pre('save', async function save(next) {
try {
if (!this.isModified('password')) return next();
const rounds = env === 'test' ? 1 : 10;
const hash = await bcrypt.hash(this.password, rounds);
this.password = hash;
return next();
} catch (error) {
return next(error);
}
});
I try to register an existing user email, this shows up:
Mongoose: users.insert({ updatedAt: new Date("Tue, 31 Oct 2017 14:48:55 GMT"), createdAt: new Date("Tue, 31 Oct 2017 14:48:55 GMT"), activationId: '9e85ddc0-be4a-11e7-8af1-ad111a9e7a07', email: '[email protected]', password: '$2a$10$pb5IuAkc65bQF9/6sLEgUuy9VGVKCBYj1ih/nMVi6r9DAKJRyH02a', firstName: 'Takis', lastName: 'Mitsos', _id: ObjectId("59f88d57479844353d5c5b3e"), tokens: [ { token: { expiresIn: 1509547735451, refreshToken: '59f88d57479844353d5c5b3e.5c1abbc11e41ff5b349d460f13cd7068a13914c4ffc312b78e17ad62b44d3719c1ee6ed88c79a5f3', accessToken: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MDk1NDc3MzUsImlhdCI6MTUwOTQ2MTMzNSwic3ViIjoiNTlmODhkNTc0Nzk4NDQzNTNkNWM1YjNlIn0.xS-eG50hQKb0o-vt7596xuGvWippSG5J59hmiQOcc44', tokenType: 'Bearer' }, kind: 'jwt' } ], active: false, __v: 0 })```
what is the need for registration and before creating the user. what is the use of this thing? can we create a user direct?
Please elaborate on this.
Looks like the environment
in these two yml files needs additional indents
https://github.com/danielfsousa/express-rest-es2017-boilerplate/blob/master/docker-compose.dev.yml
https://github.com/danielfsousa/express-rest-es2017-boilerplate/blob/master/docker-compose.prod.yml
I'm creating an API for a mobile app and would like to know the logic behind the currently implemented user model.
I'd like to know a little bit more about the intended user registration flow of the boilerplate code.
From my perspective I have two options:
For example if I want API "article"
we can use artillery.io for that
As following this boilerplate, I found this error:
TypeError: schema[parameter].validateAsync is not a function
at validate (/home/techrova/Videos/VideoStream/node_modules/express-validation/lib/index.js:18:55)
at /home/techrova/Videos/VideoStream/node_modules/express-validation/lib/index.js:26:25
at Array.map (<anonymous>)
at /home/techrova/Videos/VideoStream/node_modules/express-validation/lib/index.js:26:8
at Layer.handle [as handle_request] (/home/techrova/Videos/VideoStream/node_modules/express/lib/router/layer.js:95:5)
at next (/home/techrova/Videos/VideoStream/node_modules/express/lib/router/route.js:137:13)
at Route.dispatch (/home/techrova/Videos/VideoStream/node_modules/express/lib/router/route.js:112:3)
at Layer.handle [as handle_request] (/home/techrova/Videos/VideoStream/node_modules/express/lib/router/layer.js:95:5)
at /home/techrova/Videos/VideoStream/node_modules/express/lib/router/index.js:281:22
at Function.process_params (/home/techrova/Videos/VideoStream/node_modules/express/lib/router/index.js:335:12)
at next (/home/techrova/Videos/VideoStream/node_modules/express/lib/router/index.js:275:10)
at Function.handle (/home/techrova/Videos/VideoStream/node_modules/express/lib/router/index.js:174:3)
at router (/home/techrova/Videos/VideoStream/node_modules/express/lib/router/index.js:47:12)
at Layer.handle [as handle_request] (/home/techrova/Videos/VideoStream/node_modules/express/lib/router/layer.js:95:5)
at trim_prefix (/home/techrova/Videos/VideoStream/node_modules/express/lib/router/index.js:317:13)
at /home/techrova/Videos/VideoStream/node_modules/express/lib/router/index.js:284:7
at Function.process_params (/home/techrova/Videos/VideoStream/node_modules/express/lib/router/index.js:335:12)
at next (/home/techrova/Videos/VideoStream/node_modules/express/lib/router/index.js:275:10)
at Function.handle (/home/techrova/Videos/VideoStream/node_modules/express/lib/router/index.js:174:3)
at router (/home/techrova/Videos/VideoStream/node_modules/express/lib/router/index.js:47:12)
at Layer.handle [as handle_request] (/home/techrova/Videos/VideoStream/node_modules/express/lib/router/layer.js:95:5)
at trim_prefix (/home/techrova/Videos/VideoStream/node_modules/express/lib/router/index.js:317:13)
at /home/techrova/Videos/VideoStream/node_modules/express/lib/router/index.js:284:7
at Function.process_params (/home/techrova/Videos/VideoStream/node_modules/express/lib/router/index.js:335:12)
at next (/home/techrova/Videos/VideoStream/node_modules/express/lib/router/index.js:275:10)
at cors (/home/techrova/Videos/VideoStream/node_modules/cors/lib/index.js:188:7)
at /home/techrova/Videos/VideoStream/node_modules/cors/lib/index.js:224:17
at originCallback (/home/techrova/Videos/VideoStream/node_modules/cors/lib/index.js:214:15)
Also here is fix solution
if later this issue still open, I will create a pull request with the fix solution
Hi, I just wanna know why you add a res.end()
after a res.json()
This is a kind of secure trick when responding in an error handler?
The user controller load
function calls the errorHandler
directly instead of calling next
:
This function is called by user router:
https://github.com/danielfsousa/express-rest-es2017-boilerplate/blob/50b2992b620e06b2f3ea6112d3e3032066f9fd03/src/api/routes/v1/user.route.js#L17
The express-js example calls next(new Error('failed to load user'))
(their example shows how to handle a similar "user-loading" problem...).
I am new rest API what v1/docs suppose to return?
I realized that the mongoose connect is an async function.
Because that, it's possible that the server start without a established mongo connection. (I could generate errors).
I think in something like that:
exports.connect = async () => {
await mongoose
.connect(mongo.uri, {
useCreateIndex: true,
keepAlive: 1,
useNewUrlParser: true,
useUnifiedTopology: true,
useFindAndModify: false,
})
.then(() => console.log('mongoDB connected...'));
return mongoose.connection;
};
Or just return mongoose.connect
as a promise without then
, and await for the resolution of the promise on the other side.
What do you think about that?
Hello, I have a problem with the template, when I deploy my API on digital ocean my mongo data base erases itself after a while so, that there is no cron job etc, I lose all my collections, I tried with docker and without, same result, if anyone has any idea of the problem
I assume you have to do it on client side?
Simple JS example would be nice...
providers: {
facebook: {
name: 'facebook',
url: '/auth/facebook',
authorizationEndpoint: 'https://www.facebook.com/v2.5/dialog/oauth',
redirectUri: window.location.origin + '/',
requiredUrlParams: ['display', 'scope'],
scope: ['email'],
scopeDelimiter: ',',
display: 'popup',
oauthType: '2.0',
popupOptions: { width: 580, height: 400 }
},
google: {
name: 'google',
url: '/auth/google',
authorizationEndpoint: 'https://accounts.google.com/o/oauth2/auth',
redirectUri: window.location.origin,
requiredUrlParams: ['scope'],
optionalUrlParams: ['display'],
scope: ['profile', 'email'],
scopePrefix: 'openid',
scopeDelimiter: ' ',
display: 'popup',
oauthType: '2.0',
popupOptions: { width: 452, height: 633 }
}
}
baseUrl: 'http://localhost:3000', // Your API domain
providers: {
facebook: {
clientId: '',
redirectUri: 'http://localhost:8080/auth/callback' // Your client app URL
},
google: {
clientId: '',
redirectUri: 'http://localhost:8080/auth/callback' // Your client app URL
}
}
methods: {
authenticate: function (provider) {
this.$auth.authenticate(provider).then(function () {
// Execute application logic after successful social authentication
})
}
}
<button @click="authenticate('google')">auth Google</button>
<button @click="authenticate('facebook')">auth Facebook</button>
We can use pino and pino-colada or pino-pretty:
First of all thanks for an amazing repo. It is one of the most useful repos out there for express.
I was going through the structure of it and the only thing I couldn't completely understand was the flow of auth middleware with respect to user roles.
This part basically.
This is the link to the whole file.
const logIn = Promise.promisify(req.logIn);
const apiError = new APIError({
message: error ? error.message : 'Unauthorized',
status: httpStatus.UNAUTHORIZED,
stack: error ? error.stack : undefined,
});
try {
if (error || !user) throw error;
await logIn(user, { session: false });
} catch (e) {
return next(apiError);
}
if (roles === LOGGED_USER) {
if (user.role !== 'admin' && req.params.userId !== user._id.toString()) {
apiError.status = httpStatus.FORBIDDEN;
apiError.message = 'Forbidden';
return next(apiError);
}
} else if (!roles.includes(user.role)) {
apiError.status = httpStatus.FORBIDDEN;
apiError.message = 'Forbidden';
return next(apiError);
} else if (err || !user) {
return next(apiError);
}
req.user = user;
i think addition of a central logging mechanism using winston/bunyan would be useful.
Shall i open a pull request?
Opening docs through opn-cli using yarn postdocs
gives an error /bin/sh: 1: opn-cli: not found
as they renamed the command to be open-cli
instead of opn
.
Hello,
https://github.com/danielfsousa/express-rest-es2017-boilerplate/blob/v1.2.0/src/api/controllers/auth.controller.js#L38 seems to always pass the password condition: any password you give, returns the token.
after register when i am trying to create user i getting error of "message": "No auth token",
"stack": "Error: No auth token\n
I am using register user access token and put it to header as Athorization
The Dockerfile adds the entire project, including ".git" ".vscode" and other useless files.
I try to deploy the default project to https://dashboard.heroku.com/ but I got the error below, can you help me?
2020-03-12T07:20:52.009643+00:00 app[web.1]: npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
2020-03-12T07:20:52.016589+00:00 app[web.1]:
2020-03-12T07:20:52.016773+00:00 app[web.1]: npm ERR! A complete log of this run can be found in:
2020-03-12T07:20:52.016893+00:00 app[web.1]: npm ERR! /app/.npm/_logs/2020-03-12T07_20_52_010Z-debug.log
2020-03-12T07:20:52.092462+00:00 heroku[web.1]: State changed from starting to crashed
2020-03-12T07:20:52.073318+00:00 heroku[web.1]: Process exited with status 1
2020-03-12T07:20:52.913319+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/" host=dev-loc.herokuapp.com request_id=f7bae61b-2240-4546-9213-b30bae7ddcc1 fwd="115.79.37.163" dyno= connect= service= status=503 bytes= protocol=https
2020-03-12T07:20:53.798943+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/favicon.ico" host=dev-loc.herokuapp.com request_id=df48c384-d62e-4137-bb64-7ddd37c63e91 fwd="115.79.37.163" dyno= connect= service= status=503 bytes= protocol=https
I just clone this repo following the steps. I'm getting an error on yarn dev
error: MongoDB connection error: MongoTimeoutError: Server selection timed out after 30000 ms
[nodemon] app crashed - waiting for file changes before starting...
Mongodb version Details
db version v4.0.13
git version: bda366f0b0e432ca143bc41da54d8732bd8d03c0
OpenSSL version: OpenSSL 1.1.1 11 Sep 2018
allocator: tcmalloc
modules: none
build environment:
distmod: ubuntu1804
distarch: x86_64
target_arch: x86_64
We should have different options for deployment and they should be documented on README.md.
For starting I am thinking about choosing 2 or 3 of:
Hey, guys!
Actively using the boilerplate, thank you, it is really good!
Locally application starts the MongoDB as service, everything is fine. But on production my image contains only app itself.
So I'm using the next deployment scheme:
Build machine:
But server only runs App container, not mongo.
Is there the short way to start app with mongo on prod by the scheme i'm using?
Hey Daniel, how's it going?
I was cleaning up my API based on your boilerplate, and after changing the export to be
module.exports = mongoose.model('RefreshToken', refreshTokenSchema);
instead of
const RefreshToken = mongoose.model('RefreshToken', refreshTokenSchema);
module.exports = RefreshToken;
it broke (naturally) - I was thinking of we could improve this a bit by moving the new declaration in the controller?
Hi there!
Issue:
Previous versions of Pug/Jade supported an interpolation syntax such as:
a(href="/#{url}")
, but is not more supported in attributes.
Therefore, the link is not rendered properly in emai's action button.
Solution:
Changing following line in src/api/services/emails/passwordReset/html.pug
a.f-fallback.button.button--green(href=passwordResetUrl target='_blank' style='...')
to
a.f-fallback.button.button--green(href=passwordResetUrl target='_blank' style='...')
resolve the problem.
I may suggest a pullrequest if you wish.
Anyhow, have a good day :)
Hi.
I'm currently looking to deploy the dockerized container to my server.
I cloned the repo, cd to the directory, yarn
, cp .env.example .env
and started the docker container with yarn docker:dev
but it says NODE_ENV is missing from my .env file but I double checked and it exists, any ideas? Could you try to reproduce so I could see if the issue is only on my side.
I am planning on doing a big refactoring on this repo, since the last update was 3 years ago.
express-rest-es2017-boilerplate
to express-rest-boilerplate
Why do you need the user-controller replace
function and the /v1/users/:id
PUT api when you have the user-controller update
function and the /v1/users/:id
PATCH api?
Is this just for the example use-case (some people like to use PUT and some like to use PATCH), or is there some deeper reasoning behind this decision, like supporting some official api standard (i.e. OAuth)?
In this file we can see we require logger ('./../config/logger') which is a workaround from getting a dependency cycle warning, since logger is required in index.js as well (the entry point). Thus forming a dependency cycle.
Is this best practice? Would this cause an incomplete import from happening if this boilerplate was expanded upon in some instances?
I believe it is coming from auth.js file. Any help is appreciated.
(node:7924) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): TypeError: Promise.promisify is not a function
(node:7924) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
onst error = err || info;
console.log(req.logIn);
const logIn = Promise.promisify(req.logIn);
const apiError = new APIError({
message: error ? error.message : 'Unauthorized',
status: httpStatus.UNAUTHORIZED,
stack: error ? error.stack : undefined,
});
Any refrence on how to enable swagger documentation on the express routes ?
we can use https://github.com/godaddy/terminus
Hi,
In your tests you implement the following function:
async function format(user) {
const formated = user;
// delete password
delete formated.password;
// get users from database
const dbUser = (await User.findOne({ email: user.email })).transform();
// remove null and undefined properties
return omitBy(dbUser, isNil);
}
then you use it in _.some()
to check if an object is included in res.body
:
const bran = format(dbUsers.branStark);
const john = format(dbUsers.jonSnow);
const includesBranStark = some(res.body, bran);
const includesjonSnow = some(res.body, john);
Since format()
is an async function, it returns a Promise
, and when used as a predicate in _.some()
, it will always return true, which makes the test incorrect.
I would like to run several tasks in the server like cron or manually executed ones (like creating a super user after first install), how do you suggest to implement it?
I prefer not to deal with API calls directly since most of the commands runs on bash one liners (like a cron command).
Thanks for all your hard work on the REST Boilerplate. I used it as the basis for my company's API. I also used it as example content for my blog post about creating API documentation using Squarespace. Here is the blog post, and here is the boilerplate API reference. If you'd like, I could clean up the reference so that you can reference it on your README. Just let me know.
Regards,
John
Hey, I was just trying to run the tests and noticed async fails because I am running Node 6.x on my system.
I noticed you mention 7.x+ as requirements but before upgrading I went on to see if there's any hosting provider covering the newest Node versions and to my surprise several only support 4.x or max 6.x .. (like AWS for example)
How hard would be to re-write the parts of the boilerplate needed for >6.x node? (I imagine async/await)
Hi, how can I translate all the Joi validation messages to another language like pt_BR?
yarn dev v0.15.1 $ "nodemon ./src/index.js" sh: 1: nodemon ./src/index.js: not found error Command failed with exit code 127.
To see what happens to your code in Node.js 10, Greenkeeper has created a branch with the following changes:
.travis.yml
package.json
files, so that was left aloneIf you’re interested in upgrading this repo to Node.js 10, you can open a PR with these changes. Please note that this issue is just intended as a friendly reminder and the PR as a possible starting point for getting your code running on Node.js 10.
Greenkeeper has checked the engines
key in any package.json
file, the .nvmrc
file, and the .travis.yml
file, if present.
engines
was only updated if it defined a single version, not a range..nvmrc
was updated to Node.js 10.travis.yml
was only changed if there was a root-level node_js
that didn’t already include Node.js 10, such as node
or lts/*
. In this case, the new version was appended to the list. We didn’t touch job or matrix configurations because these tend to be quite specific and complex, and it’s difficult to infer what the intentions were.For many simpler .travis.yml
configurations, this PR should suffice as-is, but depending on what you’re doing it may require additional work or may not be applicable at all. We’re also aware that you may have good reasons to not update to Node.js 10, which is why this was sent as an issue and not a pull request. Feel free to delete it without comment, I’m a humble robot and won’t feel rejected 🤖
There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.
Your Greenkeeper Bot 🌴
"test:watch": "cross-env NODE_ENV=test mocha --watch src/api/tests/unit",
should be "test:watch": "cross-env NODE_ENV=test mocha --watch src/api/tests/integration",
Example: https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/petstore.yaml
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.