A starter project for build REST API with Express, Sequelize, PostgresSQL, supported JWT Authentication, and File Upload handler
Follow the steps below to start the application
- Clone this repo with using command on your terminal
git clone https://github.com/or-abdillh/express-starter.git
- Change current directory to application with commnd
cd express-starter
- Install node modules
npm install
This aplication using PostgreSQL as a DBMS, you must setup your information connection into file .env
- In current directory
cp .env.example .env
- Edit
.env
file with your connection setup:DATABASE_URL=postgresql://username:password@host:port/mydb SECRET_KEY=random_string_for_JWT
- Run postgres service in your computer or you can try this command
npm run postgres-start
equal topg_ctl -D ~/pg start
- Login to psql terminal and create new database using name blog
- In current directory run
npm run migrate
andnpm run seeding
- Before running command on point 5, your computer must installed sequelize-cli or you can install manual with command
npm i sequelize-cli --save-dev
In current directory running the application with command npm run dev
This application case study is a simple blog, where users can create an account and login to be able to post articles, edit articles, or delete articles. but if the user doesn't want to register, he can log in as a guest and can only see all the articles that have been posted.
This is the documentation about the API that has been made
http://localhost:8000
Testing application or index route
Response :
{
"status": true,
"code": 200,
"message": "Success",
"results": "This is example response from your application",
"createAt": "5/27/2022, 5:00:06 PM"
}
Get all users
Response :
{
"status": true,
"code": 200,
"message": "Success",
"results": {
"users": [
{
"username": "fulan12",
"fullname": "Fulanah",
"createdAt": "2022-05-26T11:38:12.544Z"
}
]
},
"createAt": "5/27/2022, 5:00:06 PM"
}
Get all articles or by query
Response :
{
"status": true,
"code": 200,
"message": "Success",
"results": {
"articles": [
{
"id": 1,
"title": "Lorem ipsum",
"content": "lorem ipsum sit amet dolor",
"image": "http://localhost:8000/images/IMG-2092302302908343.jpg",
"createdAt": "2022-05-26T11:38:12.544Z",
"user": {
"fullname": "Sandhika Galih"
}
}
]
},
"createAt": "5/27/2022, 5:00:06 PM"
}
{
"status": false,
"code": 404,
"message": "Not found",
"results": "Sorry, article not found",
"createAt": "5/27/2022, 5:00:06 PM"
}
Get article by username or author article
Response :
{
"status": true,
"code": 200,
"message": "Success",
"results": {
"articles": [
{
"id": 1,
"title": "Lorem ipsum",
"content": "lorem ipsum sit amet dolor",
"image": "http://localhost:8000/images/IMG-2092302302908343.jpg",
"createdAt": "2022-05-26T11:38:12.544Z",
"user": {
"fullname": "Sandhika Galih"
}
}
]
},
"createAt": "5/27/2022, 5:00:06 PM"
}
{
"status": false,
"code": 404,
"message": "Not found",
"results": "Sorry, article not found",
"createAt": "5/27/2022, 5:00:06 PM"
}
Get article by id article
Response:
{
"status": true,
"code": 200,
"message": "Success",
"results": {
"article": {
"id": 1,
"title": "Lorem ipsum",
"content": "lorem ipsum sit amet dolor",
"image": "http://localhost:8000/images/IMG-2092302302908343.jpg",
"createdAt": "2022-05-26T11:38:12.544Z",
}
},
"createAt": "5/27/2022, 5:00:06 PM"
}
{
"status": false,
"code": 404,
"message": "Not found",
"results": "Sorry, article not found",
"createAt": "5/27/2022, 5:00:06 PM"
}
Get JWT token from login
Request body :
{
username: 'YOUR USERNAME',
password: 'YOUR PASSWORD'
}
Response :
{
"status": true,
"code": 200,
"message": "Success",
"results": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsb2dpbiI6dHJ1ZSwidXNlcm5hbWUiOiJzYW5kaGlrYTIzNDAiLCJpYXQiOjE2NTM2NDMxODksImV4cCI6MTY1MzY0Njc4OX0.D61_9icM60wDzYgs_3Usk0AeOQ-r3ZIkCl5ingjv_B4"
},
"createAt": "5/27/2022, 5:00:06 PM"
}
{
"status": false,
"code": 404,
"message": "Not found",
"results": "Sorry, account not found or your username and password is wrong",
"createAt": "5/27/2022, 5:00:06 PM"
}
Create new account
Request body :
{
username: 'YOUR USERNAME',
password: 'YOUR PASSWORD',
fullname: 'YOUR FULLNAME',
password: 'YOUR PASSWORD'
}
Response :
{
"status": true,
"code": 200,
"message": "Success",
"results": "Success create account for fulanah",
"createAt": "5/27/2022, 5:00:06 PM"
}
{
"status": false,
"code": 403,
"message": "Forbidden",
"results": "Username has already exist",
"createAt": "5/27/2022, 5:00:06 PM"
}
JWT token verification
Request headers :
{ headers: { token: 'YOUR TOKEN' } }
Response :
{
"status": true,
"code": 200,
"message": "Success",
"results": "Your login session valid",
"createAt": "5/27/2022, 5:00:06 PM"
}
{
"status": false,
"code": 403,
"message": "Forbidden",
"results": "Your login session invalid",
"createAt": "5/27/2022, 5:00:06 PM"
}
Posting new article
Request headers :
{ headers: { token: 'YOUR TOKEN' } }
Request body :
{
title: 'YOUR TITTLE',
content: 'THE CONTENT FROM YOUR ARTICLE'
}
Request files :
{ files: { image: filesInputElement } }
Response :
{
"status": true,
"code": 200,
"message": "Success",
"results": "Success posting new article",
"createAt": "5/27/2022, 5:00:06 PM"
}
Change or update current article
Request header :
{ headers: { token: 'YOUR TOKEN' } }
Request body :
{
title: 'YOUR TITTLE',
content: 'THE CONTENT FROM YOUR ARTICLE',
id: 1
}
Request files [reupload image] :
{ files: { image: filesInputElement } }
Response :
{
"status": true,
"code": 200,
"message": "Success",
"results": "Success update article and remove old image from server",
"createAt": "5/27/2022, 5:00:06 PM"
}
{
"status": true,
"code": 200,
"message": "Success",
"results": "Success update article",
"createAt": "5/27/2022, 5:00:06 PM"
}
{
"status": true,
"code": 200,
"message": "Success",
"results": "Success update article but fail remove old image from server",
"createAt": "5/27/2022, 5:00:06 PM"
}
{
"status": false,
"code": 404,
"message": "Not Found",
"results": "Article not found",
"createAt": "5/27/2022, 5:00:06 PM"
}
Delete article from database using id article
Request header :
{ headers: { token: 'YOUR TOKEN' } }
Request body :
{ id: 1 }
Response :
{
"status": true,
"code": 200,
"message": "Success",
"results": "Success update article and image from server",
"createAt": "5/27/2022, 5:00:06 PM"
}
{
"status": true,
"code": 200,
"message": "Success",
"results": "Success update article but fail remove image from server",
"createAt": "5/27/2022, 5:00:06 PM"
}
{
"status": false,
"code": 404,
"message": "Not Found",
"results": "Article not found",
"createAt": "5/27/2022, 5:00:06 PM"
}
This application has middlewares to verify the user's JWT token when accessing sensitive resources.
In addition to token verification, this application also has a middleware tool to log every incoming request and save it in the form of a txt file.
Only works on sensitive routes i.e. user/article
. Every request that goes into that route must have an access token in the headers
Response :
{
"status": false,
"code": 403,
"message": "Forbidden",
"results": "Token cannot empty"
}
{
"status": false,
"code": 403,
"message": "Forbidden",
"results": "Illegal access, your token invalid"
}
{
"status": false,
"code": 403,
"message": "Forbidden",
"results": "You cannot access resource outside your account"
}
Each route that is accessed automatically the application will print information to the terminal
[5/27/2022, 5:41:01 PM] [403 - Forbidden] /user/register POST 96,791ms
[5/27/2022, 5:53:41 PM] [200 - OK] /user/article/hans4x POST 77,54ms
[5/27/2022, 6:18:06 PM] [404 - Not Found] /article/1 GET 29,043ms
The application will also automatically save the logging results into a file in the logs
directory and system will automatically create a new log file every day.
~/express-starter/logs/ $ ls
example-log.txt log-file-2022-26-5.txt log-file-2022-27-5.txt
To access the uploaded file use the http://localhost:8000/images
route which is relevant to the public/images
directory.
Example :
http://localhost:8000/images/IMG-203820402380.png
If you want to add a new public route in the public directory, add it to the app/index.js
file:
Code :
app.use('/YOUR-CUSTOM-PATH', express.static(path.join( process.cwd(), '/public/NEW-DIRECTORY' )))
http://localhost:8000/YOUR-CUSTOM-PATH
Every new file that comes in will be renamed automatically by using the formula:
const format = 'png'
const fileName = `IMG-${ new Date().getTime()}.${ format }`
I have created a simple front end application as an example of implementing the API which is available here coming soon
Support me with a cup of coffee and other snacks here ..
Don't forget to give me star in this repository ππ»ππ»
See my other projects on instagram @or.abdillh
Oka R Abdillah
Last edited on : 28/05/2022