Bookish
- Using relational databses
- Object-relational mappers (ORMs)
- Linking different sources of data
- The MVC model (Model-View-Controller)
- Developing effective user interfaces
Overview
We’re going to build a simple library management system. We’d like it to support the following features:
- Book Management
- The librarian can browse the catalogue of books
- Considerations: How are the books going to be sorted? By title? By author?
- Could we add a search feature?
- The librarian can edit the catalogue of books
- Add new books
- Update the details of a book
- Add a copy of an existing book
- Delete a copy of a book
- For each book, we will need details of
- The total number of copies of that book
- The number of copies that are currently available
- Which users have borrowed the other copies
- The librarian can browse the catalogue of books
- Member Management
- The librarian can see a list of library members
- With a list of the books that member currently has checked out
- The librarian can add a new member
- The librarian can edit the details of an existing member
- The librarian can see a list of library members
- Checking books in / out
- The librarian can check out a copy of a book to a user
- The librarian can check a copy of a book back in
- Notification for late returns?
There isn’t a lot of time to implement all of these features, so don’t worry if you don’t get all of them done. What’s important for this exercise is that you gain an understanding of how data moves through your system, and how to manipulate objects in your database.
Setup
The starter code
First, clone the the Bookish – JavaScript repo and follow the instructions laid out in the readme to run it. Though running it won’t achieve anything at this moment in time.
The starter code you have been provided with uses Express to provide a REST API that will sit on top of your database. The idea here is to provide endpoints that can be called to GET, POST, PUT, or DELETE data from/to your database, however, none of these endpoints have been implemented yet.
It’s worth going through what we do have in the starter code to make sure we understand what we have before we try and implement these endpoints.
Routes
This is where you define your API’s endpoints. Right now we have a single index.js
file in which you could define all your endpoints, or you could break them up across multiple files, for example a file per database table.
You can see in index.js
that we will be using Express to help us create our API and define our various routes and endpoints.
Models
Models are just classes that define what data the app should contain. Have a look at Book.js
in the models
folder to get an idea of what one looks like.
The models/
folder also contains database.js
which provides a connection to our database, and index.js
which will configure our database table stucture based on the models that we define. You don’t need to worry too much about either of these files.
Migrations
Migrations are just a series of scripts that are run in order to build up the structure of our database. We’re using Sequelize as our Migrations Framework to help make this easier, you can use it to run our migrations with the following command npx sequelize-cli db:migrate
.
Have a look at 20230124145914-create-book.js
in the migrations
folder to get an idea of what a migration looks like, this one just creates a simple table to represent a book.
config.json
This file is used by Sequelize to configure its connection to our database for running our migrations.
app.js
This file sets up our app: configuring its use of Express, which files to use as routers (routes/index.js
in our case), and setting up an error handler. You don’t need to worry about this file too much.
Setting up PostgreSQL
If you haven’t got PostgreSQL installed already, you’ll need to download and install it from the PostgreSQL website. Leave all the options as the default, but untick “Launch Stack Builder at exit” on the last screen.
When you installed PostgreSQL Server, you may have also installed pgAdmin (if not, download and install it from here). This will allow you to manage your PostgreSQL server.
Navigate to Servers > PostgreSQL > Login/Group Roles (when you’re asked for a PostgreSQL password, put in
the one you chose above for installing Postgres): right-click and create a new login/group role named
bookish
with a suitable password and privileges “Can login” and “Create databases”.
Go to Servers > PostgreSQL > Databases, right-click and create a new database named bookish
with owner
bookish
.
Make sure you can fire up PostgreSQL Server and connect to the database using pgAdmin. If you can’t, please speak to your trainer to help get it sorted.
Designing the database
You’ll need to come up with a database structure (i.e. what tables you want in your database. This is similar to deciding what classes to have in your application). Think through your database design. Work out what tables you need to support the scenarios outlined above. Discuss this with your trainers before you create things in the database.
You’re going to be using Sequelize, an ORM (object-relational mapper), to help manage the database. These help to abstract the interactions with the database by creating Models to represent the tables in your database, and Migrations to manage changes to the structure of your database.
You’ve already been provided with a migration to create a book
table and a Book
model (though they likely need a few additions), use these as inspiration to create models and migrations to define the rest of your database structure.
When writing code to connect to the database, the username/password should be the ones you set up previously
(i.e. bookish
/ <password>
) – at this stage we can put these values directly in our code, but remember this
is bad practice; such values should be externalised and passwords should be encrypted.
Building an API
Let’s start building an API that your frontend can call to in order to interact with the database.
You’ll want to start by implementing a basic endpoint: GETing all the books available in the library. You’ll find the Express routing documentation and the Sequelize querying documentation very useful for this.
First, add a new endpoint to routes/index.js
. It should define a GET request, and have a sensible route name – /books
, for example.
This endpoint should get a list of all the books in the database, and include them all in a JSON-formatted response. Have a look around the Express docs to find out how to produce a JSON response.
To test your endpoint is working, simply run the app with npm start
and use your browser or a tool like Postman to test your API endpoint and check that it’s all working as intended. Provided you followed the instructions above, the endpoint url should be http://localhost:<port>/books
. It should return a JSON-formatted list of all the books in your database. You can add some sample data to your database with pgAdmin
to test this behaviour.
Once you’re satisfied that that’s working, have a go at implementing a few more of the features in your API, starting with a POST endpoint to add a new book to the library. As your API gets bigger, maybe think about how you can organise your code differently to keep it maintainable.
As usual, be sure to ask your trainer for help if you’re not sure of something!
Build the website
Now that you’ve got the API, it’s time to start building the frontend of the website. Otherwise, people won’t actually be able to access the books they want!
We’re going to be using Vite – a dev server and bundler – to make getting everything working a bit easier. Open your terminal, go to your work directory and run
npm create vite@latest -- --template vanilla
NPM should offer to install Vite if you don’t already have it. It should prompt you for a name for the project, and then create a directory with the same name that should be populated with a basic template for a site. If you go to that directory, you should see a few different files. The ones you should pay most attention to are:
index.html
– This is where the majority of the layout of the site is definedmain.js
– This is where interactive and dynamic parts of the site are writtenstyle.css
– This contains the styling for your site
Currently, they’ll have some example content from the template. To preview the site, you enter the file that vite has created and install dependencies and run the dev server by running the following in your terminal:
npm install
npm run dev
Go to the address it shows in your browser, and a site should appear! Once you’re happy that’s working, open
index.html
. You’ll notice a div
with id="app"
. Start building out a basic structure for your site, with
a simple header and page layout, replacing the div
that’s currently there. As you’re doing this, try to keep
accessibility in mind and use correct semantic HTML elements when you can. Once you’ve got a
basic structure, you can try styling it a bit too by editing style.css
.
Adding content
You’ve got a basic structure for your site, but there’s no content yet! You’ve already made an API route for
listing all the available books, so now you can put it to use. You’ll probably find it helpful to create a
container div
with a unique, descriptive id
that you can use to put all the content in. If you open
main.js
, you’ll notice the code already there, which is used to add content to that original div
that you
replaced. Feel free to remove or comment out the code – make sure you leave the import './style.css'
though!
Now, add some code to your main.js
to call your API, retrieve the list of available books, and populate the
container you made when the site loads. You’ll want to make use of document.querySelector
to get the
container element (you can look at the template code for an example of how to use it), and the Fetch
API to make an HTTP request to your
API. This should end up looking something like:
fetch("localhost:3001/books")
.then(response => response.json())
.then(data => setMyData(data));
Once you’ve done this, you should be able to refresh the page, and see all the books listed on your page.
Interactive sites
It’s good that people can see the available books, but how are they going to add new ones to the library? You
should have an API endpoint for this too, so all you need is an interface to interact with it. Add a form to
your page so that people can submit new books. You’ll want to use the form
HTML tag. Have a look through the
MDN docs for the form
tag and see if you
can figure out how to submit data to your API. Remember to make sure you’ve set the correct method
to match
what you defined for your API.
Once you’re done with that, you should be able to submit a book, refresh the page, and have it appear along with all the other books!