-
Notifications
You must be signed in to change notification settings - Fork 208
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
feat: implement basic user component #5
Conversation
package.json
Outdated
"@loopback/repository": "^0.14.2", | ||
"@loopback/rest": "^0.19.2", | ||
"@loopback/openapi-v3": "^0.12.2" | ||
"@types/bcrypt": "^2.0.0", | ||
"bcrypt": "^3.0.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use https://github.com/dcodeIO/bcrypt.js instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason for using that modules over the one I'm using?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bcrypt
is a binary add-on and it requires compilation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And we don't want that? CI was failing before because I was running install with --ignore-scripts
. The JS version is about 30% slower according to their own docs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Plain JS module is much more desirable for an example app. It will remove a lot of support issues in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fire
package.json
Outdated
"@loopback/repository": "^0.14.2", | ||
"@loopback/rest": "^0.19.2", | ||
"@loopback/openapi-v3": "^0.12.2" | ||
"@types/bcrypt": "^2.0.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reinstall as dev dependency?
src/controllers/user.controller.ts
Outdated
} | ||
|
||
// Validate Password Length | ||
if (obj.password.length < 8) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a temporary solution to the fact that we are not supporting authentication atm? I would have assumed that the password at the framework level would have been hashed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't have a default User model like we did in LB3 which is where these checks / hashing would've been implemented. So for now people would have the flexibility to implement User
how they want.
@@ -5,7 +5,7 @@ | |||
|
|||
import {createClientForHandler, supertest} from '@loopback/testlab'; | |||
import {RestServer} from '@loopback/rest'; | |||
import {ShoppingApplication} from '../'; | |||
import {ShoppingApplication} from '../..'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is probably a good reminder for us to change the template generated by our app generator so that this file lives in the acceptance folder
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.send(user) | ||
.expect(200) | ||
// tslint:disable-next-line:no-any | ||
.expect(function(res: any) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's not all that important, but we can use the supertest's promise support here:
const response = await client.post('/users').send(user).expect(200);
// assertions
src/datasources/db.datasource.ts
Outdated
@@ -0,0 +1,14 @@ | |||
import {inject} from '@loopback/core'; |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
|
||
if [ $TASK = "test" ]; then | ||
echo "TASK => MONGODB STARTUP DELAY" | ||
sleep 10 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we have a check for mongodb service / process here instead of using sleep?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We would have to check and sleep / something if the service isn't up and ready yet anyways. This is the fix recommended by Travis themselves, documented here: https://docs.travis-ci.com/user/database-setup/#mongodb-does-not-immediately-accept-connections
bin/setup.sh
Outdated
@@ -0,0 +1,3 @@ | |||
docker rm -f mongodb_c |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we have a variable to represent the name of the container? Feel free to ignore as this can be done later if need be.
src/controllers/user.controller.ts
Outdated
) {} | ||
|
||
@post('/users') | ||
async create(@requestBody() obj: User): Promise<User> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick: I suggest we rename obj
to userObj
or user
or something along those lines
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's the default we generate using the lb4 controller
command but a good call. Will update.
src/controllers/user.controller.ts
Outdated
@get('/users/{id}') | ||
async findById(@param.path.string('id') id: string): Promise<User> { | ||
const user = await this.userRepository.findById(id); | ||
delete user.password; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if juggler can take care of this for us using some sort of flag.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this PR, do we want to have a separate datasource and docker configured for just testing? I'd imagine we don't want to run any tests on potentially existing data
.expect(415); | ||
}); | ||
|
||
it('returns a user with given id when POST /user/{id} is invoked', async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
POST -> GET
}); | ||
|
||
it('returns a user with given id when POST /user/{id} is invoked', async () => { | ||
const userWithId = Object.assign({}, user, {id: userId}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of setting userId
in a separate test, I think it's better for the user to be created in the test (through the repository), set the userId
, and then call the endpoint. This allows tests to not be dependent upon each other.
Also, the created user instances need to be deleted after each tests
Signed-off-by: virkt25 <[email protected]>
Signed-off-by: virkt25 <[email protected]>
|
||
// Save & Return Result | ||
const savedUser = await this.userRepository.create(user); | ||
delete savedUser.password; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While this is good enough for the initial implementation, it is also very brittle. We should find a more robust way how to allow models to hide certain properties from toJSON
output.
In the past, I had very good experience with moving the password to a different model (table/collection) and use hasMany
relation. As a nice side effect, by keeping a hash of all previous passwords, we can easily implement a password policy like "cannot reuse the same password".
@get('/users/{id}') | ||
async findById(@param.path.string('id') id: string): Promise<User> { | ||
const user = await this.userRepository.findById(id, { | ||
fields: {password: false}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto here.
@@ -5,7 +5,7 @@ | |||
|
|||
import {createClientForHandler, supertest} from '@loopback/testlab'; | |||
import {RestServer} from '@loopback/rest'; | |||
import {ShoppingApplication} from '../'; | |||
import {ShoppingApplication} from '../..'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let client: supertest.SuperTest<supertest.Test>; | ||
const userRepo = new UserRepository(new UserDataSource()); | ||
|
||
const user = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer us to follow our own best practices, see Use data builders.
implements the remainder of loopbackio/loopback-next#1480