There are two available options for you to use this template for your next Back End project: either use Github's built-in Use this template
feature (green button left of the 'About' section), or download the zip file and extract it in the root of a new project folder by running these commands:
wget https://github.com/NivaldoFarias/typescript-project-template/archive/main.zip
Then run the following command to install the project's dependencies:
# Using npm
npm install
# Using yarn
yarn install
That's it! You can now start developing your TypeScript Project by running the command below. Happy coding!
# Using npm
npm run dev
# Using yarn
yarn dev
While dealing with errors in a Layered Structure Project enviroment, you may notice that the project's debugging complexity scales beyond common console.log()
usage. The AppLog
Object and AppError
Object structures were set to counter that exact issue, by trying to keep the Development process as clean and concise as possible. Both are frequently referenced in the code, but do have a specific usage.
An AppError
Object is used to handle errors in the application. It that takes four parameters:
log
: A string containing a simplified error message, for Server side use. This is the message that will be used by theAppLog
ObjectstatusCode
: An integer containing the HTTP status code.message
: A string containing a simplified error message, for Client side use. This is the message that will be displayed to the user.details
: A string containing a detailed error message, for Client side use. Can be used to provide more information about the error, such as the stack trace, or suggestions on how to counter the error.
// ..../middlewares/auth.middleware.ts
import * as repository from './../repositories/auth.repository.ts';
import AppError from './../events/AppError';
...
..
async function usersExists(req: Request,...){
...
..
const user = await repository.findbyId(req.body.id);
if (!user){
throw new AppError(
'User not found',
404,
'User not found',
'Ensure to provide a valid user ID.'
);
}
..
...
}
An AppLog
Object is used to handle logs in the application. Each method corresponds to a respective color and prefix to log messages. It takes one parameter: text
: a descriptive string containing the message to be logged.
Method | Color | Log prefix |
---|---|---|
controller | Green | [Controller] |
repository | Blue | [Repository] |
middleware | Magenta | [Middleware] |
service | Cyan | [Service] |
error | Red | [Error] |
server | Yellow | [Server] |
utils | Cyan | [Utils] |
// .../middlewares/auth.middleware.ts
//...
async function validPassword(password: string) {
const isValid = await bcrypt.compare(password, user.password);
if (!isValid) {
// throw an AppError instance
}
return AppLog.middleware("Password is valid");
}
// ..../middlewares/auth.middleware.ts
import AppLog from './events/AppLog';
...
..
async function usersExists(req: Request,...){
...
..
// output: [Middleware] User Found
AppLog('Middleware', 'User found');
res.locals.user = user;
return next();
}
..
...
While aiming to provide a reusable, modular and extensible architecture, the middlewares are generally the first structures to be refactored into self-contained modules. The validateSchema()
, processHeader()
and requireToken()
middlewares were set in order to achieve that goal. The following section describes useMiddleware()
, which incorporates the forementioned functions as key–value pairs in an Object, along with their structure and usage.
The useMiddleware()
function takes two parameters:
middlewares
: An Object containing the key–value pairs of the middlewares to be used, takes one to three parameters:schema
: A Joi Schema Object that will be used to validate the data provided by the client. If the data provided by the client is not valid, anAppError
Object will be thrown.header
: A string containing the name of the header that will be used to authenticate the action. If the client-provided header is missing, anAppError
Object will be thrown.token
: A boolean indicating whether the token provided by the client will be verified or not. If the token is not valid, anAppError
Object will be thrown.
endpoint
: A string that will be used to identify the endpoint at which the client–api interaction is undergoing, which will be logged to console by theAppLog
Object.
Reference: useMiddleware function declaration
// ..../routes/admin.route.ts
import useMiddleware from '../utils/middleware.util';
import * as schema from '../models/admin.model';
...
..
const endpoint = '/admin';
const registerEndpoint = '/create';
adminRouter.post(endpoint,
createEndpoint,
useMiddleware({
schema: schema.create,
header: 'admin-api-key',
token: true
},
endpoint + createEndpoint),
middleware.createValidations,
controller.create,
);
..
...
In this section, you will find the example API's endpoints and their respective descriptions, along with the request and response examples, as well as the Prisma models for each entity, that can be used as guide for data formatting. All data is sent and received as JSON.
id
: A unique identifier for each user.serial4
username
: The user's username.text
email
: The user's email. An email may only be registered once.text
password
: The user's password.text
created_at
: The date and time when the user was created.timestamp
Authentication /auth
{
"username": "johndoe",
"email": "john_doe@gmail.com",
"password": "123456789"
}
{
"Content-Type": "application/json"
}
Status Code | Description | Properties |
---|---|---|
201 | Created | data: {} |
409 | Email already registered | error: { message, details } |
422 | Invalid Input | error: { message, details } |
500 | Internal Server Error | error: { message, details } |
{
"email": "john_doe@gmail.com",
"password": "123456789"
}
{
"Content-Type": "application/json"
}
Status Code | Description | Properties |
---|---|---|
200 | OK | data: { token } |
403 | Invalid password | error: { message, details } |
404 | User not found | error: { message, details } |
422 | Invalid Input | error: { message, details } |
500 | Internal Server Error | error: { message, details } |