Skip to content

sam-rice/reading-room-api

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Reading Room API

Deployed Site


This is the home of the Reading Room API, the back-end service of a full-stack personal project.

Repository for the project's React/Next.JS UI can be found here.


Back End

Abstract

Reading Room is a full-stack web application that allows users to browse and catalogue a virtual library of books. New users can be registered, authenticated, and create custom "shelves"—individual collections of books. Books with corresponding user notes can then be edited or added/removed from each shelf. Within the "browse" section of the app, users can search for new books by title or author name. The app's target users are modern book-lovers who need an instant, mobile way to search for new books and keep track of their book collections.

The REST API is built with Java/Spring Boot, Docker, and PostgreSQL, and leverages the Open Library API for all book and author data. The service is deployed via Heroku and configured with unrestricted access for demoing purposes. See API Reference below for demoing the API with Postman. Instructions for registering/authenticating users via JSON Web Token, creating/updating/deleting shelves and books, and querying data are also outlined below, in addition to project setup instructions for running the application locally.

The project also includes a JUnit integration test suite for all repository classes, which leverages an H2 in-memory database.


Table of Contents


Project Architecture Diagram

RR High-Level Architecture Diagram

Entity Relationship Diagram

RR Entity Relationship Diagram copy

Local Setup Instructions

Running this project and/or integration tests locally requires installations of JRE, JDK 17, Docker Desktop, and an IDE of your choice. Maven is also required and can either be installed locally, or accessed via IDE plugin.

  1. Clone this repository to your machine.
  2. Open Docker Desktop.
  3. From the command line, navigate to the top level of the project repository and run docker-compose up to start the Postgres database.
  4. Open the project with your IDE and run the application to spin up the server.

Note that when running locally, the project is configured to seed all database tables with data for demo purposes. Stopping and starting the server will drop, create, and re-seed the tables.


API Reference

Usage Overview

All endpoints besides "User" endpoints (user log in and register) require a valid authentication token in the request header to recieve a successful response. To recieve an auth token cookie, use the /users/login endpoint to log in as an existing user or create a new one using the /users/register endpoint (User endpoints). Auth tokens are valid for 2 hours. Proper header formatting shown below (note the space between "Bearer" and token):

{ "Authorization": "Bearer <Auth Token>" }

To get started, login as an existing demo user or register a new user.

Demo User:

email: [email protected] password: guitar

A Note on Semantics

The Open Library API refers to an author's individual works as "works," while treating individual editions of a work as "books." The current version of this application simply treats an author's individual works as "books" and does not expose data unique to any specific edition. As a result, the code for this project includes POJO interfaces for JSON deserialization that refer to works and books according to Open Library's semantics. This is important to keep in mind for understanding the source code of this project. For example, a JSON response from Open Library being recieved by this API may start as a "work," and once deserialized, be morphed into a "book" along with other data returned from a set of aggregated requests to Open Library.

Any book saved to a user's shelf includes a bookId and libraryKey field. A bookId is unique to every saved book, while a libraryKey is used for integrating with Open Library, and is used for fetching a book's details via the book details endpoint. For example, a user could save several "copies" of one book—all of which have the same libraryKey field—that each have a unique bookId.


Base URL

  DEPLOYED: https://reading-room-api-d84cba6ce967.herokuapp.com/api

  LOCAL: http://localhost:8080/api

Persistence Endpoints

User Endpoints

Register New User

  /users/register
MethodRequest BodySuccessful ResponseSet-Cookie Header Value Example
POST { "firstName": string, "lastName": string, "email": string, "password": string } { "firstName": string, "lastName": string, "email": string } "token=eyJhbGciOiJIUzI1NiJ9.eyJpYXQiOj; Path=/; Expires=Sat, 01 Jan 72000 08:00:00 GMT; Secure; HttpOnly"

* Correct email format required.


Log In Existing User

  /users/login
MethodRequest BodySuccessful ResponseSet-Cookie Header Value Example
POST { "email": string, "password": string } { "firstName": string, "lastName": string, "email": string } "token=eyJhbGciOiJIUzI1NiJ9.eyJpYXQiOj; Path=/; Expires=Sat, 01 Jan 72000 08:00:00 GMT; Secure; HttpOnly"


Shelf Endpoints

Get All Shelves by Active User

  /shelves
MethodRequest BodySuccessful Response
GET n/a { "shelfId": number, "userId": number, "title": string, "description": string, "totalSavedBooks": number }[]

Get Shelf by Id

  /shelves/{shelfId}
MethodRequest BodySuccessful Response
GET n/a { "shelfId": number, "userId": number, "title": string, "description": string, "totalSavedBooks": number, "books": { "bookId": number, "shelfId": number, "userId": number, "libraryKey": string, "title": string, "authors": { name: string, libraryKey: string }[], "coverUrl": string | null, "userNote": string | null, "savedDate": number }[] | null }

Create New Shelf

  /shelves
MethodRequest BodySuccessful Response
POST { "title": string, "description": string } { "shelfId": number, "userId": number, "title": string, "description": string, "totalSavedBooks": number }

Update Shelf

  /shelves/{shelfId}
MethodRequest BodySuccessful Response
PUT { "title": string, "description": string } { "success": boolean }

Delete Shelf

  /shelves/{shelfId}
MethodRequest BodySuccessful Response
DELETE n/a { "success": boolean }


Book Endpoints

Get Book by Id

  /shelves/{shelfId}/books/{bookId}
MethodRequest BodySuccessful Response
GET n/a { "bookId": number, "shelfId": number, "userId": number, "libraryKey": string, "title": string, "authors": { name: string, libraryKey: string }[], "coverUrl": string | null, "userNote": string | null, "savedDate": number }

Create New Book/Add to Shelf

  /shelves/{shelfId}/books
MethodRequest BodySuccessful Response
POST { "libraryKey": string } { "bookId": number, "shelfId": number, "userId": number, "libraryKey": string, "title": string, "authors": { name: string, libraryKey: string }[], "coverUrl": string | null, "userNote": string | null, "savedDate": number }

Update Book

  /shelves/{shelfId}/books/{bookId}

* Note: Only userNote field can be updated.

MethodRequest BodySuccessful Response
PUT { "userNote": string | null } { "success": boolean }

Delete Book

  /shelves/{shelfId}/books/{bookId}
MethodRequest BodySuccessful Response
DELETE n/a { "success": boolean }

Library Search Endpoints

Note: query parameters in endpoints should replace whitespace with %20

Author Search Endpoints

Author Search by Name

  /search/authors?q={authorName}&size={numberOfResultsPerPage}&page={pageNumber}
MethodRequest BodySuccessful Response
GET n/a { "totalResults": number, "pageSize": number, "pageNum": number, "results": { "libraryKey": string, "name": string, "birthDate": string | null, "deathDate": string | null, "topBook": string | null, "topSubjects": string[] | null }[] }

Author Details

  /search/authors/{authorLibraryKey}
MethodRequest BodySuccessful Response
GET n/a { "libraryKey": string, "name": string, "bio": string | null, "photoUrl": string | null, "birthDate": string | null, "deathDate": string | null, "books": { "libraryKey": string, "title": string, "publishDate": string, "primaryAuthor": { "name": string, "libraryKey": string }, "byMultipleAuthors": boolean, "coverUrl": string | null, "subjects": string[] | null }[] | null, }

Book Search Endpoints

Book Search by Title

  /search/books?q={bookTitle}&size={numberOfResultsPerPage}&page={pageNumber}
MethodRequest BodySuccessful Response
GET n/a { "totalResults": number, "pageSize": number, "pageNum": number, "results: { "libraryKey": string, "title": string, "publishYear": number | null, "editionCount": number, "authors": { "name": string, "libraryKey": string }[], "coverUrl": string | null, "subjects": string[] | null }[] }

Book Details

  /search/books/{bookLibraryKey}
MethodRequest BodySuccessful Response
GET n/a { "libraryKey": string, "title": string, "description": string | null, "publishDate": string | null, "authors": { "name": string, "libraryKey": string }[] "coverUrl": string | null, "subjects": string[] | null, "associatedShelves": { "shelfId": number, "title": string }[] }

About

REST API for a book cataloguer web app

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published