/book_api

Book api with search.

Primary LanguagePythonMIT LicenseMIT

📚 Book API

This project allow to add .epub books (they will be handled and added to DB (book name, author name, names and texts of chapters)), search in book with query, returning cutted fragment of found text.

Quick overview

Project using:

Installation guide

  1. Clone current repo: git clone https://github.com/xaer981/book_api.git
  2. Go to the new dir and create .env file from example: cd book_api/ && cp default.env .env
    • ADMIN_USER - username for using in HTTP Basic auth to add new books to DB
    • ADMIN_PASSWORD - password for using in HTTP Basic auth to add new books to DB
    • DB_URL - default url to get access to DB from FastAPI(postgresql://postgres:postgres@book_api-db/{name of DB})
    • POSTGRES_USER
    • POSTGRES_PASSWORD
    • POSTGRES_DB - name of DB. If not default, also need to change in DB_URL
    • POSTGRES_INITDB_ARGS - using here for locale (needed for correct search in books), if books will be in english use POSTGRES_INITDB_ARGS="--locale=en_US", and change "russian" to "english" in /app/db/crud -> search_in_book -> query_func + func.ts_headline inside "if results".
    • REDIS_URL - default url to get access to Redis from FastAPI
  3. Go to 'infra' dir and start container: cd infra/ && docker-compose up -d
  4. Server started! It's available on localhost:8000/{endpoint}/
  5. OpenAPI docs are on localhost:8000/docs/ and on localhost:8000/redoc/
  6. Add your first book! The easiest way to do it is using redoc. Go to localhost:8000/redoc/, then "Authorize" (use credentials from your .env file), then "Try it out" on "POST /books/", attach your .epub book and "Execute".

Usage

  1. Adding book via localhost:8000/docs/.

    • Click "Authorize" image
    • Use credentials from your .env file and "Authorize" again image
    • Click "Try it out" in "POST /books/" image
    • Choose your .epub file and "Execute" image
    • Success! You just added a new book. image
  2. Enpoints.

    • Get all books -> GET /books/ image
    • Get books with pagination -> GET /books/?size={desired size}&page={desired page} image
    • Get chapters of book -> GET /books/{book_id}/ image
    • Get text of chapter -> GET /books/{book_id}/chapter/{chapter_number}/ image
    • Search chapters in book containing query -> GET /books/{book_id}/search/ + body = {"query": "your query"} image
    • Get all authors -> GET /authors/ image
    • Get authors with pagination -> GET /authors/?size={desired size}&page={desired page} image
    • Get books of author -> GET /authors/{author_id}/ image

Technical details

  1. About credentials.

    • If you're using something without auto encoding of credentials, you should get credentials encoded in base64 to use in HTTP Basic auth.
    • To get encoded credentials, you can use "encode_bs64.py" from "core". Just add ADMIN_USER and ADMIN_PASSWORD in .env (described above) and run this file python app/core/encode_bs64.py (also need to install dotenv python -m pip install python-dotenv or use "encode_credentials" function separately.
    • Add header "Authorization" with value Basic {your encoded in base64 credentials}.
  2. About cache.

    • Project using custom cache key builder (needed to cache paginated results correctly) -> app/core/cache.py "custom_key_builder". If you're not going to use pagination, just delete "key_builder=..." from app/main.py -> "lifespan" function -> FastAPICache.init.
    • Project also using custom cache coder (needed to cache results made with pydantic models ORM correctly).
    • Lifetime. I think that permanent cache meets the requirements of this project. Redis cache flushing on FastAPI shutdown and after adding every new book in DB. If you want to use cache with expire time, just add expire={time in seconds} to every "cache()" decorator in app/main.py.
  3. About pagination.

    • Pagination turned on in two endpoints: GET /authors/ and GET /books/. If you want to turn it off, change response_model=CustomPage[AuthorInfo] in app/main.py -> "author_list" function -> "@app.get" decorator to response_model=AuthorInfo. Same with app/main.py -> "book_list" function -> "@app.get" decorator.

Finally

If you have any troubles or just want to improve something, feel free to open issues or PRs.

Do not hesitate to contact me 👉 Telegram 👈