An exercise on Express API creation, Databases and Sequelize.
- To setup an Express API using node-postgres, Sequelize, Mocha/Chai and Supertest for testing.
- Use advanced Sequelize schema validation, error handling and establish complex relationships between database tables.
In order to create this App, I was presented with an imaginary client's requests. I was to create an app that allowed them to do the following:
- Display their books to be loaned by other users.
- Loan other users' books.
- Create an account that would secure their personal information.
I generated an ERD so I could design the database before starting to write any code. This is how I envisioned the project's structure.
I would create the following Models:
Reader ✅
param | data type |
---|---|
Reader_ID | INT (PK) |
Name | STRING |
Book_ID | INT(FK) |
It will include the Book Model data of referenced entries.
Book ✅
param | data type |
---|---|
Book_ID | INT (PK) |
Title | STRING |
ISBN | STRING |
Loaned | BOOLEAN |
Reader_ID | INT (FK) |
Genre_ID | INT (FK) |
Author_ID | INT (FK) |
Loan_ID | INT (FK) |
It will include the Reader, Genre and Author Model data of referenced entries.
Author ✅
param | data type |
---|---|
Author_ID | INT (PK) |
Name | STRING |
Book_ID | INT (FK) |
Author and Genre are individual models to support searches (by Author, Genre or Book) through the library.
Genre ✅
param | data type |
---|---|
Genre_ID | INT (PK) |
Genre | STRING |
Book_ID | INT (FK) |
Author and Genre are individual models to support searches (by Author, Genre or Book) through the library.
Account 🚧
param | data type |
---|---|
Account_N | INT (PK) |
STRING | |
Password | STRING |
Reader_ID | INT (FK) |
STILL TO BE IMPLEMENTED:
For now, Account data is stored in the Reader Model.
Loan 🚧
param | data type |
---|---|
Loan_ID | INT (PK) |
Date_Loaned | DATE |
Date_Returned | DATE |
Returned | BOOLEAN |
Account_N | INT (FK) |
Book_ID | INT (FK) |
STILL TO BE IMPLEMENTED
This version supports:
- Creating your own Reader entry that safely stores your personal information.
- Creating & Updating a list of the Books you own.
- Search by Author, Genre or Book.
This version does not include the Loan & Account models nor any functionality or parameter related to them. These will be included in further updates.
- Set up Docker to run a postgres container:
docker run --name postgres -p 5432:5432 -e POSTGRES_PASSWORD=password -d postgres
-
Run pgAdmin 4 and create a new server:
- hostname/address: localhost
- user: postgres
- password: password
-
Fork this project. Then clone the repo to your machine:
git clone git@github.com:[your-github-username]/book-library-api
- Install the project's dependencies:
npm install
- In the root of your project, create a .env file and a .env.test file. Specify in them your environment variables.
PGPASSWORD=password
PGDATABASE=book_library_dev
PGUSER=postgres
PGHOST=localhost
PGPORT=5433
Make sure your PGPORT matches the one assigned in your pgAdmin4 Server!
Make sure your PGDATABASE names are different in your .env & .env.test files!
- Use the following commands to:
npm test # Test code.
npm start # Start the app in your preferred port (3000 by default).
- You can interact with the API and test its functions through Postman.
POST
/readers
(creates a new reader entry)
Parameters Body content None Name [STRING], Email [STRING], Password [STRING](8 characters or more)
code description 201
Successful operation 400
Content element empty, null, not unique, not the right format or not the right length
GET
/readers
(returns all the reader entries)
Parameters Body content None None
code description 200
Successful operation 404
Entry not found
GET
/readers/:id
(returns a reader entry by ID)
Parameters Body content Reader_ID
None
code description 200
Successful operation 404
Entry not found
PATCH
/readers/:id
(updates a reader entry by ID)
Parameters Body content Reader_ID
Name [STRING], Email [STRING], Password [STRING](8 characters or more)
code description 200
Successful operation 404
Entry not found
DELETE
/readers/:id
(deletes a reader entry by ID)
Parameters Body content Reader_ID
None
code description 204
Successful operation 404
Entry not found
POST
/books
(creates a new book entry)
Parameters Body content. Required. None Title [STRING], ISBN [INT], Author_ID [INT], Genre_ID [INT], Reader_ID [INT]
code description 201
Successful operation 400
Content element empty, null or not unique
GET
/books
(returns all book entries)
Parameters Body content None None
code description 200
Successful operation 404
Entry not found
GET
/books/:id
(returns a book entry by ID)
Parameters Body content Book_ID
None
code description 200
Successful operation 404
Entry not found
PATCH
/books/:id
(updates a book entry by ID)
Parameters Body content Book_ID
Title [STRING], ISBN [STRING], Author_ID [INT], Genre_ID [INT] and/or Reader_ID [INT]
code description 200
Successful operation 404
Entry not found
DELETE
/books/:id
(deletes a book entry by ID)
Parameters Body content Book_ID
None
code description 204
Successful operation 404
Entry not found
POST
/authors
(creates a new author entry)
Parameters Body content None Name [STRING]
code description 201
Successful operation 400
Content element empty, null or not unique
GET
/authors
(returns all the author entries)
Parameters Body content None None
code description 200
Successful operation 404
Entry not found
GET
/authors/:id
(returns an author entry by ID)
Parameters Body content Author_ID
None
code description 200
Successful operation 404
Entry not found
PATCH
/authors/:id
(updates an author entry by ID)
Parameters Body content Author_ID
Name [STRING]
code description 200
Successful operation 404
Entry not found
DELETE
/authors/:id
(deletes an author entry by ID)
Parameters Body content Author_ID
None
code description 204
Successful operation 404
Entry not found
POST
/genres
(creates a new genre entry)
Parameters Body content None Genre[STRING]
code description 201
Successful operation 400
Content element empty, null or not unique
GET
/genres
(returns all the genre entries)
Parameters Body content None None
code description 200
Successful operation 404
Genres not found
GET
/genres/:id
(returns a genre entry by ID)
Parameters Body content Genre_ID
None
code description 200
Successful operation 404
Entry not found
PATCH
/genres/:id
(updates a genre entry by ID)
Parameters Body content Genre_ID
Genre [STRING]
code description 200
Successful operation 404
Entry not found
DELETE
/genres/:id
(deletes a genre entry by ID)
Parameters Body content Genre_ID
None
code description 204
Successful operation 404
Entry not found
I have been using Mocha, Chai and Supertest to write test suites trying the functionality of the API. This is the result for the current version when running npm test
:
Test Results
/authors
with no records in the database
POST /authors
✔ creates a new author in the database (770ms)
✔ errors if name is null
with records in the database
GET /authors
✔ gets all authors records
GET /authors/:id
✔ gets authors record by id
✔ returns a 404 if the author does not exist
PATCH /authors/:id
✔ updates authors name by id
✔ returns a 404 if the author does not exist
DELETE /authors/:id
✔ deletes author record by id
✔ returns a 404 if the author does not exist
/books
with no records in the database
POST /books
✔ creates a new book in the database
✔ errors if title is null
with records in the database
GET /books
✔ gets all books records
GET /books/:id
✔ gets books record by id
✔ returns a 404 if the book does not exist
PATCH /books/:id
✔ updates books title by id
✔ returns a 404 if the book does not exist
DELETE /books/:id
✔ deletes book record by id
✔ returns a 404 if the book does not exist
/genres
with no records in the database
POST /genres
✔ creates a new genre in the database
✔ errors if genre is null
with records in the database
GET /genres
✔ gets all genres records
GET /genres/:id
✔ gets genres record by id
✔ returns a 404 if the genre does not exist
PATCH /genres/:id
✔ updates genres genre by id
✔ returns a 404 if the genre does not exist
DELETE /genres/:id
✔ deletes genre record by id
✔ returns a 404 if the author does not exist
/readers
with no records in the database
POST /readers
✔ creates a new reader in the database
✔ errors if email format not valid
✔ errors if any fields are missing
✔ errors password is less than 8 char length
with records in the database
GET /readers
✔ gets all readers records
GET /readers/:id
✔ gets readers record by id
✔ returns a 404 if the reader does not exist
PATCH /readers/:id
✔ updates readers email by id
✔ returns a 404 if the reader does not exist
DELETE /readers/:id
✔ deletes reader record by id
✔ returns a 404 if the reader does not exist
38 passing (3s)