You need to have npm installed to run this project, you can check if you have it installed by running npm -v
in the command line.
Clone the repository on your computer. Detailed instructions can be found here.
Database connection doesn't work without .env in root folder. .env is set to be ignored by git with .gitignore, so create one locally. By default the backend server will start on port 3000, which can be changed by setting PORT
environment variable. Make sure backend and frontend are using different ports.
Here's an example of a .env file you can use:
#Backend
DATABASE_SERVER=
DATABASE_NAME=
DATABASE_USER=
DATABASE_PASSWORD=
OIDC_AUTH_BACKLINK_URL=
OIDC_AUTH_REDIRECT_URL=
PORT=
#MySQL
MYSQL_DATABASE=
MYSQL_USER=
MYSQL_PASSWORD=
MYSQL_ROOT_PASSWORD=
MYSQL_PORT=
You will need to run the backend application and the database. You can have them separately, or you can use docker-compose.
Database initialization is handled automatically on creation using the *.sql files in the /sql folder.
If you have Windows, make sure you have Docker Desktop running before running the command. https://www.docker.com/products/docker-desktop/
docker-compose -f docker-compose-dev.yml up -d
docker-compose -f docker-compose-staging.yml up -d
docker-compose -f docker-compose-test.yml up -d
The -f flag specifies the file since there are different ones. The -d flag (detach) runs the container in the background allowing you to close the terminal without killing the process.
Use npm ci
or npm install
to install node modules.
Start the backend by running npm start
.
There are two workflow files that run on this repository: node.js.yml and deploy-staging.yml.
The Node.js CI workflow is designed to ensure code quality and functionality before changes are merged. It triggers on every push or when a pull request is made to development
, main
, or s23-staging
branches. Here's a step-by-step breakdown of the workflow:
- Code Formatting Check: Utilizes Prettier to ensure code is following the project's formatting standards.
- Backend Spin-up: Initiates the backend and employs
wait-on
to verify when the URL is available. A timeout here often indicates an issue with container/app build. - Robot Tests: Executes robot tests to verify code functionality. If tests fail, review and update your code or the tests accordingly.
The Prettier workflow is set up in the code with Pretty-quick (https://github.com/azz/pretty-quick) and Husky (https://typicode.github.io/husky/) to ensure consistent formatting. Pretty-Quick checks formatting when a developer tries to commit to the repo, and fixes formatting using our prettier config (.prettierrc.json file in the root of the project). Husky ensures that the pre-commit checks works with a pre-commit hook. Make sure you have all dependencies installed by running: npm install
before you start. In your code editor, you can also set prettier checks on save, which will help the process.
Endpoints that use body will be in JSON format. Endpoint requires either query or body, if query is present, the body section will not be shown and vice versa.
If not separately mentioned, On Success Response schema is:
{
"ok": true
}
If not separately mentioned, On Fail Response schema is:
{
"ok": false
}
Show Endpoints
Body
{
"username": string,
"email": string,
"password": string
}
On Success Response schema:
{
"ok": true,
"secret": string
}
On Fail Response schema:
{
"ok": false,
"message": string
}
Body
{
"email": string,
"password": string
}
On Success Response schema:
{
"ok": true,
"userId": number,
"secret": string
}
On Fail Response schema:
{
"ok": false,
"message": string
}
On Fail Response schema:
{
"ok": false,
"message": string
}
Show Endpoints
On Success Response schema:
[
{
"id": number,
"library_user": number,
"title": string,
"image": string,
"author": string,
"year": number,
"topic": string,
"isbn": string,
"deleted": boolean,
"homeOfficeId": number,
"homeOfficeName": string,
"homeOfficeCountry": string
}
]
pageSize is optional
On Success Response schema:
[
{
"id": number,
"library_user": number,
"title": string,
"image": string,
"author": string,
"year": number,
"topic": string,
"isbn": string,
"deleted": boolean,
"homeOfficeId": number,
"homeOfficeName": string,
"homeOfficeCountry": string
}
]
On Success Response schema:
number
On Success Response schema:
{
"id": number,
"library_user": number,
"title": string,
"image": string,
"author": string,
"year": number,
"topic": string,
"isbn": string,
"deleted": boolean,
"homeOfficeId": number,
"homeOfficeName": string,
"homeOfficeCountry": string
}
On Success Response schema:
{
"id": number,
}
Body:
{
"library_user": number,
"title": string,
"image": string,
"author": string,
"year": number,
"isbn": string,
"topic": string,
"homeOfficeId": string
}
Body:
{
"id": number,
"title": string,
"image": string,
"author": string,
"year": number,
"isbn": string,
"topic": string,
"homeOfficeId": string,
}
On Success Response schema:
[
{
"id": number,
"library_user": number,
"title": string,
"image": string,
"author": string,
"year": number,
"topic": string,
"isbn": string,
"deleted": boolean,
"homeOfficeId": number,
"homeOfficeName": string,
"homeOfficeCountry": string
}
]
Show Endpoints
On Success Response schema:
[
{
"id": number,
"library_user": number,
"name": string
}
]
On Fail Response schema:
{
"ok": false,
"status": 500
}
On Success Response schema:
[
{
"id": number,
"library_user": number,
"name": string
}
]
On Fail Response schema:
{
"ok": false,
"status": 500
}
On Success Response schema:
[
{
"id": number,
"library_user": number,
"title": string,
"image": string,
"author": string,
"year": number,
"topic": string,
"isbn": string,
"deleted": boolean,
"homeOfficeId": number,
"homeOfficeName": string,
"homeOfficeCountry": string
}
]
On Success Response schema:
{
"userId": number,
"username": string,
"name": string
}
On Success Response schema:
{
"id": number,
"library_user": number,
"name": string
}
On Fail Response schema:
{
"ok": false,
"status": 500
}
Body:
{
"id": number,
"name": string
}
On Fail Response schema:
{
"ok": false,
"status": 500
}
Body:
{
"id": number,
"name": string
}
On Fail Response schema:
{
"ok": false,
"status": 500
}
Body:
{
"id": number
}
On Fail Response schema:
{
"ok": false,
"status": 500
}
Show Endpoints
On Success Response schema:
[
{
"id": number,
"list": number,
"book": number
}
]
On Fail Response schema:
{
"ok": false,
"status": 500
}
On Success Response schema:
[
{
"id": number,
"list": number,
"book": number
}
]
On Fail Response schema:
{
"ok": false,
"status": 500
}
On Success Response schema:
{
"id": number,
"list": number,
"book": number
}
On Fail Response schema:
{
"ok": false,
"status": 500
}
Body:
{
"list": number,
"book": number
}
On Fail Response schema:
{
"ok": false,
"status": 500
}
Body:
{
"id": number
}
On Fail Response schema:
{
"ok": false,
"status": 500
}
Body:
{
"listId": number,
"bookId": number
}
Show Endpoints
On Success Response schema:
[
{
"id": number,
"userId": number,
"isbn": string,
"title": string,
"reason": string,
"status": Book_request_status
}
]
Body:
{
"userId": number,
"isbn": string,
"title": string,
"reason": string
}
Body:
{
"id": number,
"status": Book_request_status
}
Show Endpoints
Bookreservations are considered active, if they are not canceled, loaned, and the connected Borrow hasn't been returned more than RESERVATION_DAYS prior to now. Book_reservations are considered loanable, if they are active and the connecting Borrow has been returned. Book_reservation status isn't automatically updated in the backend, but is instead filtered through SQL queries and _filterActiveReservations function in queries/book_reservation.
On Success Response schema:
[
{
"id": number,
"userId": number,
"bookId": number,
"borrowId": number,
"reservationDatetime": Date,
"loaned": boolean,
"canceled": boolean
}
]
On Success Response schema:
[
{
"id": number,
"userId": number,
"bookId": number,
"borrowId": number,
"reservationDatetime": Date,
"loaned": boolean,
"canceled": boolean,
"returnDate": Date | null
}
]
[
{
"id": number,
"bookId": number,
"reservationDatetime": Date,
"loaned": boolean,
"canceled": boolean,
"returnDate": Date
}
]
On Success Response schema:
[
{
"id": number,
"username": string,
"image": string,
"title": string,
"bookId": number,
"reservationDatetime": Date,
"loaned": boolean,
"canceled": boolean,
"returnDate": Date | null
}
]
Body:
{
"bookId": number
}
On Success Response schema:
[
{
"id": number,
"userId": number,
"bookId": number,
"borrowId": number,
"reservationDatetime": Date,
"loaned": boolean,
"canceled": boolean,
"returnDate": Date | null
}
]
Body:
{
"userId": number,
"bookId": number
}
Body:
{
"bookId": number
}
Body:
{
"reservationId": number
}
Body:
{
"userId": number,
}
Show Endpoints
On Success Response schema:
[
{
"id": number,
"user_id": number,
"book_id": number,
"comment": string,
"rating": number,
"review_date": Date
}
]
Body:
{
"bookId": number
}
On Success Response schema:
[
{
"id": number,
"user_id": number,
"book_id": number,
"comment": string,
"rating": number,
"review_date": Date
}
]
Body:
{
"bookId": number
}
On Success Response schema:
{
"averageRating": number
}
Body:
{
"reviewId": number
}
Body:
{
"bookId": number,
"comment": string,
"rating": number
}
Body:
{
"comment": string,
"rating": number,
"reviewId": number
}
Show Endpoints
On Success Response schema:
[
{
"id": number,
"library_user": number,
"book": number,
"dueDate": Date,
"borrowDate": Date,
"returned": boolean,
"returnDate": Date | null
}
]
On Success Response schema:
{
"id": number,
"library_user": number,
"book": number,
"dueDate": Date,
"borrowDate": Date,
"returned": boolean,
"returnDate": Date | null
}
Body:
{
"id": number
}
Body:
{
"userId": number,
"bookId": number,
"dueDate": Date,
"borrowDate": Date,
"returned": boolean
}
On Fail Response schema:
{
"ok": false,
"message": string
}
Body:
{
"id": number,
"library_user": number,
"book": number,
"dueDate": Date,
"borrowDate": Date,
"returned": boolean,
"returnDate": Date | null
}
On Success Response schema:
[
{
"id": number,
"library_user": number,
"book": number,
"dueDate": Date,
"borrowDate": Date,
"returned": boolean,
"returnDate": Date | null
}
]
On Success Response schema:
[
{
"borrowId": number,
"dueDate": Date,
"title": string,
"bookId": number,
"username": string,
"userId": number
}
]
On Success Response schema:
[
{
"username": string,
"title": string,
"borrowDate": Date,
"dueDate": Date,
"id": number
}
]
On Success Response schema:
[
{
"id": number,
"library_user": number,
"book": number,
"dueDate": Date,
"borrowDate": Date,
"returned": boolean,
"returnDate": Date | null
}
]
On Success Response schema:
[
{
"id": number,
"library_user": number,
"book": number,
"dueDate": Date,
"borrowDate": Date,
"returned": boolean,
"returnDate": Date | null
}
]
Body:
{
"id": number,
"library_user": number,
"book": number,
"dueDate": Date,
"borrowDate": Date,
"returned": boolean,
"returnDate": Date | null
}
Show Endpoints
Body:
{
"bookId": number
}
On Success Response schema:
{
"isFavorited": boolean
}
Body:
{
"bookId": number
}
On Success Response schema:
{
"count": number
}
Body:
{
"bookId": number
}
Body:
{
"bookId": number
}
Show Endpoints
Body:
{
"id": number,
"name": string,
"countryCode": string
}
Body:
{
"id": number,
"name": string,
"countryCode": string
}
Body:
{
"id": number
}
Body:
{
"id": number,
"name": string,
"countryCode": string
}
Show Endpoints
On Success Response schema:
{
"ok": true,
"secret": string
}
Body:
{
"id": number,
"username": string,
"email": string,
"passw": string,
"administrator": boolean,
"homeOfficeId?": number
}
On Fail Response schema:
{
"ok": false,
"message": string
}
Show Endpoints
On Success Response schema:
[
{
"id": number,
"username": string,
"email": string,
"administrator": boolean,
"deleted": boolean,
"homeOfficeId?": number
}
]
On Success Response schema:
{
"id": number,
"username": string,
"email": string,
"administrator": boolean
}
On Success Response schema:
{
"id": number,
"username": string,
"email": string,
"administrator": boolean,
"deleted": boolean
}
Body:
{
"id": number
}
Body:
/user?username={username}&email={email}&password={password}&administrator={administrator}
/user?id={id}&username={username}&email={email}&password={password}&administrator={administrator} (PUT)
/user/admin?id={id}&username={username}&email={email}&administrator={administrator} (PUT)