Ktor REST API for a Bookshelf Manager
Build a REST API in Kotlin for managing your personal book collection: add books with their title, author, genre and reading status (want to read, reading, finished), update them as you read, and search by title or author or filter by status. It's built with Ktor, JetBrains' framework for web servers in Kotlin, stores data in SQLite through the Exposed library, and is fully tested with Ktor's test engine without starting a real server. You'll learn routing, JSON with kotlinx.serialization, validation and status codes, database access with Exposed, organizing code into layers, and integration testing.
- Estimate
- ~10h
- Steps
- 6
- Completed by
- 0
- Proposed by
- codeseed.app
Ktor · Exposed · SQLite
Project roadmap
- 01
Set up the Ktor project
~1.5hGenerate a project at start.ktor.io (or with the IntelliJ plugin) with the Routing, Content Negotiation, kotlinx.serialization and Status Pages plugins. Add a GET /health route. Done when: the server starts and /health returns OK.
- 02
Define the database
~1.5hAdd Exposed and the SQLite JDBC driver. Define a Books table with the Exposed DSL: id, title, author, genre, pages, status (an enum), rating (1 to 5, optional), added at and finished at. Connect at startup and create the table with SchemaUtils. Put the queries in a BookRepository class. Done when: books can be inserted and read through the repository.
- 03
Add the CRUD endpoints
~2hAdd GET /books, GET /books/{id}, POST /books, PUT /books/{id} and DELETE /books/{id}, using @Serializable request and response classes separate from the table. Return 201 with the new book on create, 404 for unknown ids, and 204 on delete. Set finished at automatically when the status changes to finished. Done when: every endpoint works with curl and returns the right status codes.
- 04
Validate and handle errors
~1.5hValidate requests: the title and author are required (up to 200 characters), pages are between 1 and 10,000, and the rating is between 1 and 5 and only allowed for finished books. Use Status Pages to turn validation errors into 400 with a list of problems, malformed JSON into 400, and unexpected errors into 500 without internal details. Done when: invalid input gets clear 400 responses.
- 05
Add search and filters
~1.5hSupport GET /books?q=&status=&genre=&sort=title|author|added&page=&size=. q searches title and author, ignoring case. Build the query conditionally with Exposed, and return the items with the total count. Add GET /books/stats with counts by status and pages read this year. Done when: search, filters and sorting combine correctly.
- 06
Write integration tests
~2hWrite tests with testApplication and a fresh in-memory or temporary SQLite database per test: creating and fetching books, updates setting finished at, validation errors, 404s, search and filters, and stats. Done when: ./gradlew test passes.
Resources
Ready to build this?
Get a GitHub repo and start building. Your AI reviewer checks each step as you go.
Tech stack