REALMS: 一个图书管理系统
REALMS Establishes A Library Management System, written in Go, using a MySQL database.
Introduction to Database Systems (H) @ Fudan University, spring 2020.
Getting started
0 Prerequisities
To set up the environment, you need to have the following dependencies installed.
For Windows, try MinGW-w64.
1 Installation
First, you need to obtain the REALMS package.
Then you can build the project using Make.
|
|
For MinGW-w64 on Windows, use the command below.
|
|
You should see the following output, which indicates a successful installation.
2 Usage
2.1 realmsd - the backend
Run realmsd using the command below, and the server will listen to port 7274
by default.
|
|
Realmsd will open a database connection to a MySQL database, originally at root:Hakula@tcp(localhost:3306)/library
. You can modify the configuration in the config file ./configs/db_config.json
. There’s no need to manually create a database named library
, as it’ll be created automatically in advance.
2.2 realms - the frontend
To interact with the backend, here’s a simple CLI tool, namely, realms. Though, it’s not necessarily required, since you can easily build another frontend with the RESTful APIs, a guide for which will be provided later.
Run realms using the command below.
|
|
You should see the welcome message.
To get started with REALMS, use the command help
to show all available commands.
|
|
|
|
It’s quite easy to understand how these commands work, nevertheless we’re going to introduce them in detail in the next chapter.
3 REST API
Here we’ll demonstrate the usage of these RESTful APIs by example.
3.1 Log in
3.1.1 Request
Method: POST /login
Content-Type: multipart/form-data
CLI command: login
In realms:
You’ll be required to enter your username and password (FYI, the password is invisible while typing). There’s no signup
in REALMS, so a user account can only be acquired from an admin.
To authenticate a user’s credentials, REALMS uses the session. In the implementation of realms, a session cookie is used to store the essential information, and the cookies are handled by cookiejar.
On the server-side, the password will be hashed using bcrypt before save.
3.1.2 Response
Status: 200 OK
Content-Type: application/json
|
|
In case of a successful login, you’ll receive a welcome message.
|
|
Otherwise, an error will be returned. If the server didn’t return a response, realms will print the following message.
|
|
Other possible error messages are shown below.
3.2 Log out
3.2.1 Request
Method: GET /logout
CLI command: logout
In realms:
|
|
3.2.2 Response
Status: 200 OK
Content-Type: application/json
|
|
In case of a successful logout, you’ll receive a success message.
|
|
Otherwise, an error will be returned. Possible error messages are shown below.
3.3 Show current logged-in user
3.3.1 Request
Method: GET /user/me
CLI command: me
In realms:
|
|
User privilege is required, which means you have to login before doing this operation.
3.3.2 Response
Status: 200 OK
Content-Type: application/json
|
|
Normally, your user ID will be returned.
|
|
If you’re not logged in, you’ll receive an error message below.
|
|
3.4 Show the current login status
3.4.1 Request
Method: GET /status
CLI command: status
In realms:
|
|
3.4.2 Response
Status: 200 OK
Content-Type: application/json
|
|
If the current user is logged in, you’ll see the following message.
|
|
3.5 Add a new book
3.5.1 Request
Method: POST /admin/books
Content-Type: application/json
CLI command: add book
In realms:
Admin privilege is required. In REALMS, we use level
to indicate a user’s privilege, which is a property of the user model. When a user makes a request, the server will check if he/she has admin privilege. If not, an Unauthorized Error will be returned.
You’ll be required to input the necessary information of the book, and the title
field should not be blank, or an error will be returned. To skip an optional field in realms, simply press Enter.
On the server-side, the following message will be written to log using zap. The default path to the log file is ./logs/realmsd.log
, which can be modified in the config file ./configs/log_config.json
.
|
|
3.5.2 Response
Status: 200 OK
Content-Type: application/json
The complete information of the added book will be returned, since you may want to display it in your front-end application. For the sake of simplicity, here realms will just print the book ID.
|
|
If not authorized (i.e. you’re not an admin), you’ll receive an error message below.
|
|
3.6 Update data of a book
3.6.1 Request
Method: PATCH /admin/books/:id
Content-Type: application/json
CLI command: update book
In realms:
Admin privilege is required.
Here :id
refers to the book ID, which realms will prompt the user for input at the beginning.
Simply sending a request including just the fields that you want to update is fine, and empty values will be omitted. Still, there’s an input checker for all inputs on the server-side, which will validate your request body to prevent invalid requests.
The following message will be written to log.
|
|
3.6.2 Response
Status: 200 OK
Content-Type: application/json
The updated data will be returned.
|
|
Possible error messages are shown below.
3.7 Remove a book
3.7.1 Request
Method: DELETE /admin/books/:id
Content-Type: application/json
CLI command: remove book
|
|
In realms:
Admin privilege is required.
The message
field is optional, which is the explanation why you remove the book.
The following message will be written to log.
|
|
Or if there’s no explanation:
|
|
3.7.2 Response
Status: 200 OK
Content-Type: application/json
|
|
Since the book has already been removed, there’s no need to return its information.
|
|
Possible error messages are shown below.
3.8 Show all books
3.8.1 Request
Method: GET /books
CLI command: show books
In realms:
|
|
3.8.2 Response
Status: 200 OK
Content-Type: application/json
|
|
We expect the following output, aligned in table style.
|
|
Here the column width can be customized in realms, which is 25
by default. Overflowed content will be hidden.
If there’s no book found, realms will print the following message.
|
|
In the implementation of realms, when handling distinct responses, generally we use an interface{}
to represent the unknown data type (which can be bool
, int
, string
, map[string]interface{}
). However, when it comes to this response, the returned data is in fact a []map[string]interface{}
, which cannot be asserted directly. So here’s a workaround.
|
|
3.9 Show the book of given ID
3.9.1 Request
Method: GET /books/:id
CLI command: show book
In realms:
3.9.2 Response
Status: 200 OK
Content-Type: application/json
Output:
Possible error messages are shown below.
|
|
3.10 Find books by title / author / ISBN
3.10.1 Request
Method: POST /books/find
Content-Type: application/json
CLI command: find books
To search by title (fuzzy, case-insensitive):
|
|
To search by author (fuzzy, case-insensitive):
|
|
To search by ISBN (exact, case-insensitive):
|
|
To search by title and author:
etc.
In realms:
3.10.2 Response
Status: 200 OK
Content-Type: application/json
|
|
Output:
|
|
If there’s no book found, realms will print the following message.
|
|
3.11 Add a new user
3.11.1 Request
Method: POST /admin/users
Content-Type: application/json
CLI command: add user
In realms:
Admin privilege is required.
The username should be unique. As for the privilege level:
Level | Privilege |
---|---|
1 | User |
2 | Admin |
3 | Super Admin |
The following message will be written to log.
|
|
3.11.2 Response
Status: 200 OK
Content-Type: application/json
Output:
|
|
Possible error messages are shown below.
3.12 Update data of a user
3.12.1 Request
Method: PATCH /admin/users/:id
Content-Type: application/json
CLI command: update user
In realms:
Admin privilege is required.
Here :id
refers to the user ID. The level
field is optional.
The following message will be written to log.
|
|
3.12.2 Response
Status: 200 OK
Content-Type: application/json
Output:
|
|
Possible error messages are shown below.
3.13 Remove a user
3.13.1 Request
Method: DELETE /admin/users/:id
CLI command: remove user
In realms:
Admin privilege is required.
The following message will be written to log.
|
|
3.13.2 Response
Status: 200 OK
Content-Type: application/json
|
|
Output:
|
|
Possible error messages are shown below.
3.14 Show all users
3.14.1 Request
Method: GET /admin/users
CLI command: show users
In realms:
|
|
Admin privilege is required.
3.14.2 Response
Status: 200 OK
Content-Type: application/json
It’s obvious that we don’t need to display the hashed passwords here.
Possible error messages are shown below.
|
|
3.15 Show the user of given ID
3.15.1 Request
Method: GET /admin/users/:id
CLI command: show user
In realms:
Admin privilege is required.
3.15.2 Response
Status: 200 OK
Content-Type: application/json
Output:
Possible error messages are shown below.
3.16 Borrow a book
3.16.1 Request
Method: POST /user/books/:id
Content-Type: application/json
CLI command: borrow book
|
|
In realms:
- Debug mode:
true
- Debug mode:
false
User privilege is required.
Here we add a debug mode for testing purpose, since it’s impossible to keep waiting for several weeks until the borrowed book is overdue. When debug mode is enabled, a user can input the borrowing date manually, otherwise it will be set to the current date and time.
The following message will be written to log.
|
|
3.16.2 Response
Status: 200 OK
Content-Type: application/json
The default return date is 14
days after the borrowing date. You may change it in the config file ./configs/library_config.json
.
If a user has more than 3
overdue books not returned (the limit may also be customized), his/her account will be suspended, which means he/she is no longer allowed to borrow another book before returning the overdue books. In that case, an error will be returned.
|
|
If the book has already been borrowed by the current user before, here comes another error.
|
|
Other possible error messages are shown below.
3.17 Return a book
3.17.1 Request
Method: DELETE /user/books/:id
CLI command: return book
In realms:
User privilege is required.
In the implementation of realmsd, the record is soft deleted, which means it will not be actually removed from the table. Instead, we use a delete_at
column to store the time when the record is removed (the book is returned). Therefore, these records are temporarily ignored in most queries, but can still be obtained using the command show history
, which we will introduce later.
The following message will be written to log.
|
|
3.17.2 Response
Status: 200 OK
Content-Type: application/json
|
|
Output:
|
|
If the book has not been borrowed by the current user before, an error will be returned.
|
|
Other possible error messages are shown below.
|
|
Why there’s not a book not found
error here? It’s to prevent the case that an admin removed a book which had been borrowed, and now the user who borrowed it wants to return it back.
3.18 Check the deadline to return a book
3.18.1 Request
Method: GET /user/books/:id
CLI command: check ddl
In realms:
User privilege is required.
3.18.2 Response
Status: 200 OK
Content-Type: application/json
Output:
Possible error messages are shown below.
3.19 Extend the deadline to return a book
3.19.1 Request
Method: PATCH /user/books/:id
CLI command: extend ddl
In realms:
User privilege is required.
3.19.2 Response
Status: 200 OK
Content-Type: application/json
By default, the return date is extended by 7
days per request, and a user can extend the deadline for at most 3
times. You may change them in the config file ./configs/library_config.json
.
If a user tries to extend for more than 3
times, an error will be returned.
|
|
Other possible error messages are shown below.
3.20 Show all books that you’ve borrowed
3.20.1 Request
Method: GET /user/books
CLI command: show list
In realms:
|
|
User privilege is required.
3.20.2 Response
Status: 200 OK
Content-Type: application/json
|
|
Output:
If there’s no record found, realms will print the following message.
|
|
Possible error messages are shown below.
|
|
3.21 Show all overdue books that you’ve borrowed
3.21.1 Request
Method: GET /user/overdue
CLI command: show overdue
In realms:
|
|
User privilege is required.
3.21.2 Response
Status: 200 OK
Content-Type: application/json
|
|
The records will be ordered by return date in ascending order.
Possible error messages are shown below.
|
|
3.22 Show all your records
3.22.1 Request
Method: GET /user/history
CLI command: show history
In realms:
|
|
User privilege is required.
3.22.2 Response
Status: 200 OK
Content-Type: application/json
|
|
The records will be ordered by record ID in descending order. Here returned date is equal to real_return_date
in the response, which is the same as the delete_at
column in the database. That’s why we use a soft delete.
Possible error messages are shown below.
|
|
Design
4 Database schema
There’re currently 3 tables in database library
, namely, books
, users
and records
.
4.1 books
Field | Type | Null | Key |
---|---|---|---|
id | int(10) unsigned | NO | PRI |
title | varchar(255) | NO | / |
author | varchar(255) | YES | / |
publisher | varchar(255) | YES | / |
isbn | varchar(255) | YES | / |
4.2 users
Field | Type | Null | Key |
---|---|---|---|
id | int(10) unsigned | NO | PRI |
username | varchar(255) | NO | UNI |
password | varchar(255) | NO | / |
level | int(10) unsigned | NO | / |
4.3 records
Field | Type | Null | Key |
---|---|---|---|
id | int(10) unsigned | NO | PRI |
user_id | int(10) unsigned | NO | / |
book_id | int(10) unsigned | NO | / |
return_date | datetime | NO | / |
extend_times | int(10) unsigned | NO | / |
deleted_at | datetime | YES | / |
TODOs
- Add unit tests