Course: "NestJS: The Complete Developer's Guide" by Stephen Grider.
App overview | API design | Module design |
---|---|---|
npm i @nestjs/typeorm typeorm sqlite3
Database name is db.sqlite as written in the appModuleinside the TypeOrmModule object. Starting your development server in the terminal will cause a file called db.sqlite to be generated in the root of the project (I've added this file to gitignore since I don't know if iit's safe to upload it to github). https://github.com/follow-course/nestjs-car-api/blob/d631aadd2303e97bd730b16bee615be66ebb7e6d/src/app.module.ts#L12
- Create an entity file: The class in the fiile will list all the properties that your entity will have.
- Connect the entity to it's parent moduule - this creates an entity.
- Connect the entity to the root i.e. the appModule.
You will only be able to view the generated db.sqlite file the first time you open it up with the editor. To view the DB's content, you need to install an external extension or program. Using vscode extension:
- Install "SQLite" from vscode extension
- Still in vscode, go to view > command pallete
- Search for "SQLite: open database"
- Click on the database name which is same as the one in the root of your project
After these, you'll find a "sqlite explorer" collapsible dropdown towards the bottom of your vscode explorer. You will find your DB content in there.
Synchronize: true
should only be used in development, and should not be used in production. SQL database is usually very rigid. To make any changes to the structure of an SQL database/table (e.g. create or remove tables or columns, or even changing the type of data stored iin the columns), you would usually need to write "migration" code. By setting synchronize to true, typeORM will automatically do such migration. It is dangerous to use this in production so that you don't accidentally delete data for example. You need to write migration code for production.
Check out the repository API for the different methods you can use on a DB at the typeORM's official documentation. The diagram below shows and gives brief explanation of some repository methods used in this project:
Note: Yellow portin not needed for our app. Those routes are only created to help understand typeORM.
The white list property on the validation pipe is a security measure that helps to weed out properties not stated upfront in the Dto file. For example, the user is only allowed to submit email and password fields. If user tries to add a field or property e.g. admin and sets it to true (so that he/she can do things that only admins are supposed to be ale to do), the whitelist property on the validation pipe will ensure such is does not padd through. https://github.com/follow-course/nestjs-car-api/blob/54980c6be3074d2507c68defb787b392d5c1ad7d/src/main.ts#L9
The password property for example shouldn't be passed along with data from our api when we attempt to get, post, delete etc. Nest js suggests that you Exclude the response property from within thhe .entity.ts file and with the in built ClassSerializerInterceptor
used inside of the controller. While this works/helps for the case we are currently using it for, it can't help if you need to separate the response for a regular user from that of the admin. The best way is to build your own custom interceptor and create a Dto file that will expose only properties you want to be included in the response (See commits on Feb 23, 2022).
Note: The methods inside AuthService can instead be inside of the UserService if the application is small. But in large applications it is better that this separate AuthService is created. The AuthService depends on the UserService.
Passwords should not be stored directly as plain strings in the database... Salt and hash the password before storing for security reasons.
Use these inbuilt node packages: randomBytes
to generate a salt (i.e. a string of random letters) and scrypt
which is thhe hashing function for hashing your password. Note that naturally, scrypt would make us uuse a callback - the promisify
package ensures that it instead returns a promise not a callback.
Run test with:
npm run test:watch
Testing auth service: AuthService depends on the usersService, the usersService also depends on the (user) repository. We will therefore need to create a fake usersService to avoid complications. We are also only using/testing the .find() and .create() methods of the (fake) usersService since those are the only methods called (somewhere in the signin and signup methods of the authService). See diagrams and comments in the test file for more details.
About .find() and .create() methods, they are asynchronous in nature (i.e. it takes some amount of time to read or write data into the sqlite database). This is why they are made to return a promise. Promise.resolve(value) method creates a promise and immedately resolves it with a given value. It ensures that we get the exact api functionality that exists on the real usersService.
You can dramatically speed up your tests by updating the package.json file.
In the scripts section, find the following line:
"test:watch": "jest --watch",
And change it to:
"test:watch": "jest --watch --maxWorkers=1",
Restart your test runner at your terminal after making this change