VALORIZA - Project created at NLW Together , Special Edition Rocketseat bootcamp, the project is an API created with Node.js technology by instructor Daniele Leão .
Main technologies used in the construction of this application.
The project consists of a praise platform, which we can praise and return praise from within the application.
- User Registration
- Tag Registration (possible compliments)
- Admin User Only
- Register of Compliments
- User ID
- Tag ID
- Creation Date
-
User Authentication
- Generate JWT Token
- Validate user logged in required routes
- User List
- Tag Listing
- List of compliments by users
The development environment setup for this application is here .
Note
The environment setup page in Notion was created by Rocketseat.
Node.js is a JavaScript runtime built on top of Chrome's V8 JavaScript Engine and that allows the execution of JavaScript code outside of a web browser, the technology was created by Ryan Dahl and its main characteristic and differential is the execution of requests/events in single-thread and the main advantage of use is the use of the same technology in the backend and in the frontend .
APIs (Application Programming Interface) are a set of patterns that are part of an interface and that allow the creation of platforms in a simpler and more practical way for developers. From APIs it is possible to create different software, applications, programs and platforms. For example, apps developed for Android phones and iPhone (iOS) are created from defined standards and made available by the APIs of each operating system .
The REST or RESTFul standard that is defined as REST API, also called RESTful API , is an application programming interface (API or web API) that conforms to the restrictions of the REST architecture style, allowing interaction with web services RESTful. REST stands for representational transfer of state. This architecture was defined by computer scientist Roy Fielding . REST is not a protocol or standard, but rather a set of architectural constraints. API developers can implement the REST architecture in a variety of ways. When a client makes a request using a RESTful API, that API transfers a representation of the resource's state to the requester or endpoint. This information (or representation) is delivered via HTTP using one of several possible formats: Javascript Object Notation (JSON) , HTML , XLT, programming languages or plain text . The JSON format is the most used programming language because, despite its name, it is independent of any other language and can be read by machines and humans.
Typescript is an open source language developed by Microsoft that is built on top of Javascript, which is very widespread these days. So this “superset” was created to add static typing capabilities to the original language.
Method | Description |
---|---|
GET | Search for information |
POST | Insert (create) information |
PUT | Change information |
DELETE | Remove an information |
PATCH | Change specific information |
To create the first route in typescript, we first need to start the application with yarn.
$ yarn init -y
Then we need to install modules for our server, let's use typescript with development module.
$ yarn add typescript -D
and express - a minimalist framework for building web servers.
$ yarn add express
and the express type package as a development module.
$ yarn add @types/express -D
Let's create a typescript file: index.ts
In the first line we import the express, using the import.
import express from 'express';
On the next line we need to initialize the express inside the app constant.
const app = express();
Then we need to pass the app with the get method and pass the resource, which in this case is our route, as test, after an arrow function that have a request and a response as parameters.
Command | Description |
---|---|
Request | Submit a data request |
Response | Respond to a data request |
Inside the function, we pass the response with the send method, opening parentheses and quotation marks, we write a response message.
app.get('/test', (request, response) => {
response.send('Hi humans!');
})
On the next line we start the server with the app with the method listen, which will listen to our port, so we need to pass the port, which will be port 3001.
app.listen(3001, () => console.log('Hi humans!'));
Now we need to initialize the typescript
$ yarn tsc
The typescript also needs a configuration file to work within the project.
$ yarn tsc --init
We will also use a module to monitor the server called ts-node-dev .
yarn add ts-node-dev
Then we have to create a script inside the package.json file.
"scripts": {
"dev": "ts-node-dev index.ts"
},
To finally run our server locally:
$ yarn dev
Now if everything is ok, we can access the url
For Insomnia configuration, I read an article that shows how to configure it, but I also recommend this video from Rocketseat that shows you how to do it.
We need to pass the app with the post method and pass the resource, testPost, after an arrow function. Inside the function, we pass the response with the send method, opening parentheses and quotation marks, we write a response message.
app.post('/testPost', (request, response) => {
response.send('Hi guys!');
})
Before continuing API development it is very important that we define the application database structure.
The image above is a non-accurate representation of what the entity relationship diagram would look like.
Types of Parameters used in REST Requests:
Parameter | Objective | Use case | Exemples |
---|---|---|---|
Query Params | Receives the request data as a parameter in the URL. | Filters to query the application by url | http://localhost:3001/produtos?name=teclado&description=tecladobom |
Route params | Receives the request data on the route. | Best way to search for something specific, delete or update using unique identifier. | GET:http://localhost:3001/produtos/teclado PUT:http://localhost:3001/produtos/teclado DELETE:http://localhost:3001/produtos/teclado/718391938192 |
Body Params | Receives the request data in the request body, in a JSON object. | Always using the POST method and sent in the request JSON format. | { "product": "keyboard", "description": "good keyboard", "price": 250 } |
There are three ways to connect and use the database in the application with Node.js. Using the native database driver, using a query builder, the most used in Node.js is the Knex.js, and using a ORM (Object-relational mapping), and the most used in Node.js are the Sequelize and the TypeORM. We use a **ORM**, specifically the **TypeORM**, for ease of database maintenance and direct conversion between a relational database and a language Object Oriented.
The first step to configure TypeORM in the application is to install the modules.
Installing the TypeORM module
$ yarn add typeorm
you also need to install reflect-metadata to add metadata consistently in various use cases, such as objects as decorators.
$ yarn add reflect-metadata
and import it into a global location in our API.
$ import "reflect-metadata";
the Node.js typing package, and a database driver, in this case, we will use SQLite initially .
$ yarn add sqlite3
Among the various options, to quickly create an initialization file within a project that is already in progress, you can run the command:
$ typeorm init
It is still possible to use the same command with more options, to start a project.
$ typeorm init --name projectName --database sqlite3
In this case, we will use a JSON file. To do this, let's create a ormconfig.json
file in our project directory,
in this project, so as not to risk changes in the project, let's create the file without using the command, and add whatever is necessary.
{
"type": "sqlite",
"database": "src/database/database.sqlite"
}
In the first line type we add the bank type. In the next one, database, we add the location of the database. For this database it is necessary to create an index.ts
.
import { createConnection } from "typeorm"
createConnection()
To create the database file we have to indicate it in an index file inside the database on the server and finally run the server.
import './database';
After that the SQLite database file is created.
Migrations help database versioning during development, which usually avoid writing of SQL scripts and do how bank updates through of the programming language itself and frameworks used.
First, we need to reference within the cli parameter, where our recognized migrations are stored.
{
"type": "sqlite",
"database": "src/database/database.sqlite",
"cli": {
"migrationsDir": "src/database/migrations"
}
}
Second, we need to create a script in package.json to run the TypeORM cli to create the migrations
"scripts": {
"typeorm": "ts-node-dev ./node_modules/typeorm/cli.js"
}
Then just create the first migration using the CLI.
$ yarn typeorm migration:create -n CreateUsers
This command will create a migration with a timestamp and table name which is CreateUsers. Within this query we will be able to create our tables for the database.
import {
MigrationInterface,
QueryRunner,
Table
} from "typeorm";
export class CreateUsers1631066606706 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: "users",
columns: [
{
name: "id",
type: "uuid",
isPrimary: true,
},
{
name: "name",
type: "varchar",
},
{
name: "email",
type: "varchar",
},
{
name: "admin",
type: "boolean",
default: false,
},
{
name: "created_at",
type: "timestamp",
default: "now()",
},
{
name: "updated_at",
type: "timestamp",
}
]
})
)
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropTable("users")
}
}
In addition to MigrationInterface, and QueryRunner, used to run an SQL query, you need to import the Table, which will allow you to create a new SQL table inside a TypeScript (JavaScript) file inside an Up function to up a query or down to delete this query if it is not possible to create it. The ID type - UUID is an acronym for universally unique identifier, the term globally unique identifier is also widely used, but in general terms they are unique solidary pseudorandoms, for practical purposes what is generated is practically impossible to duplicate. The other column types are basic data structure knowledge.
VARCHAR
is a variable length string and can be a maximum of 8000 characters.
BOOLEAN
is a primitive data type that has two values, 0 or 1, false or true. Named boolean in honor of George Boole , who defined an algebraic logic system for the first time in half of the nineteenth century. It is used in logical operations such as conjunction , disjunction , exclusive disjunction , logical equivalence and negation , personal to some of the operations of Boolean algebra .
TIMESTAMP
is a string denoting the time or data that a certain event occurred and represents a specific point on the timeline and takes into account the time zone in question (UTC).
To run this migration we need to inform where migrations are located, within the migrations parameter.
{
"type": "sqlite",
"database": "src/database/database.sqlite",
"migrations": [ "src/database/migrations/*.ts" ],
"cli": {
"migrationsDir": "src/database/migrations"
}
}
Then we just need to run this migration in the terminal and that's it, for that we need to run the command below and it will create our table in the database.
$ yarn typeorm migration:run CreateUsers
Entity is a thing, concrete or abstract, including associations between them, abstracted from the real world and modeled in the form of a table that will store information in the database. Inside an ORM it works by receiving the application data in the Entity, passing the information through the ORM, which will transcribe this code into SQL, and transferring this information or change to the database.
To create an entity with TypeORM we need to define where this entity is inside our application, for that inside ormconfig.json
{
"type": "sqlite",
"database": "src/database/database.sqlite",
"migrations": [ "src/database/migrations/*.ts" ],
"cli": {
"migrationsDir": "src/database/migrations",
"entitiesDir": "src/entities"
}
}
Now you need to run a command in the cli to create the entity inside the entities folder referenced in ormconfig.json
$ yarn typeorm entity:create -n User
Then we can see the User.ts file inside the entities folder, and it already creates a base of what the entity will actually be. But before continuing, we must enable experimentalDecorators and emitDecoratorMetadata, so that we can work with decorators.
{
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
import { Entity } from "typeorm";
@Entity()
export class User {
};
In the decorator Entity we need to pass as parameter the name of the entity, inside the class User we have to define all the attributes already set in the CreateUsers migration, we also need to define its columns, id, as PrimaryColumn, string, number, and boolean type columns are defined only as Column, whereas date columns, precision of a special type, the creation column The date change column is defined as CreateDateColumn, the date change column is defined as UpdateDateColumn.
import {
Entity,
PrimaryColumn,
Column,
CreateDateColumn,
UpdateDateColumn
} from "typeorm";
@Entity("users")
export class User {
@PrimaryColumn()
id: string;
@Column()
name: string;
@Column()
email: string;
@Column()
admin: boolean;
@CreateDateColumn()
created_at: Date;
@UpdateDateColumn()
updated_at: Date;
};
Finally, we need to configure the UUID library inside the entity, for the same, we need to download it.
$ yarn add uuid
And also your type library.
$ yarn add @types/uuid
Now you need to import this module into the Entity
import { v4 as uuid } from 'uuid';
We also need to define the id column as readonly, so in case of a possible update of this user, it cannot be changed, and can only be defined within this entity.
@PrimaryColumn()
readonly id: string
Finalizing the entity, for this ID, we need to create a constructor with an instruction, if it comes with a null value, define it as UUID.
constructor() {
if(!this.id) {
this.id = uuid();
}
}
Repository is the layer or part of the ORM that makes a connection between Entity and Database. Its purpose is to isolate objects and as a domain entity in the database.
I'll leave a script on how to clone and run the app in development
Clone this repository
$ git clone https://github.com/franciscoarmando63/valoriza.git
Access the project folder in terminal/cmd or powerhell
$ cd valoriza
Install dependencies
$ yarn install .
Run the application in development mode with ts-node-dev.
$ yarn dev
The server will start on port: 3001 - go to