Card 04/ 11
Resource Example: A Bookshop's Books, Authors and Reviews
Three related resources, and the paths that reach them without repeating any.
Deriving paths from a domain means turning its nouns into collections, its relationships into sub-collections or links, and giving each resource one canonical path. A bookshop sells books, each written by one or more authors, and readers write reviews of books. The trace takes it from nouns to paths, one decision per frame.
InputBooks, authors and reviews; a review belongs to one book
The nouns
- booknoun
- author
- review
Each thing a client needs to name is a candidate resource.
Each noun becomes a collection
- /books
- /authors
- /books/{id}/reviewsnested
A review exists only for one book, so its collection sits under the book.
Each collection gains an item path
- /books/{id}
- /authors/{id}
- /reviews/{id}canonical
A review has its own id, so one review is reached at the top level.
The many-to-many link becomes a sub-collection
- /authors/{id}/bookslink
- authorIds in each book
- /books/{id}/reviews
Listing an author's books is a filtered view of /books, not a second copy.
ResultSix paths cover the domain, and each book, author and review has exactly one canonical URL.
The final set, with the methods each path takes:
GET, POST /books
GET, PATCH, DELETE /books/{id}
GET, POST /books/{id}/reviews
GET, PATCH, DELETE /reviews/{id}
GET, POST /authors
GET, PATCH /authors/{id}
GET /authors/{id}/booksWhy reviews are created under the book. POST /books/12/reviews says which book the review is for in the path, so the body does not need to.
Why one review is read at the top level. /reviews/3 stays valid even if the review moves between books, and a client holding only the review id does not need the book id.
Why /authors/{id}/books is read-only. It is a view onto /books filtered by author. Creating a book there would give books two places to be created.
← → move through sections and cards