Skip to main content

REST support for bareASGI

Project description

bareASGI-rest

This package provides enhanced support for writing REST APIs with bareASGI, (read the docs).

It includes:

  • A router to simplify the creation of REST APIs,
  • A swagger API endpoint

This is a Python 3.8+ package.

Installation

The package can be installed from pypi.

$ pip install bareASGI-rest

An ASGI server will be required to run the code. The examples below use uvicorn.

$ pip install uvicorn

Usage

The router provided by this package maps the arguments and types of request handlers.

We will create a mock book repository.

Creating typed dictionaries

Here is the type of a book. We use TypedDict to allow automatic type discovery

from datetime import datetime
from typing import TypedDict


class Book(TypedDict):
    """A Book

    Args:
        book_id (int): The book id
        title (str): The title
        author (str): The author
        published (datetime): The publication date
    """
    book_id: int
    title: str
    author: str
    published: datetime

Note: the docstring will be used to provide documentation for swagger.

Creating the API

Now we can build the API.

from typing import Dict, List

from bareasgi_rest import RestError


BOOKS: Dict[int, Book] = {}
NEXT_ID: int = 0

async def get_books() -> List[Book]:
    """Get all the books.

    This method gets all the books in the shop.

    Returns:
        List[Book]: All the books
    """
    return list(BOOKS.values())


async def get_book(book_id: int) -> Book:
    """Get a book for a given id

    Args:
        book_id (int): The id of the book

    Raises:
        RestError: 404, when a book is not found

    Returns:
        Book: The book
    """

    if book_id not in BOOKS:
        raise RestError(404, "Book not found")

    return BOOKS[book_id]


async def create_book(
        author: str,
        title: str,
        published: datetime
) -> int:
    """Add a book

    Args:
        author (str): The author
        title (str): The title
        published (datetime): The publication date

    Returns:
        int: The id of the new book
    """
    NEXT_ID += 1
    BOOKS[NEXT_ID] = Book(
        book_id=NEXT_ID,
        title=title,
        author=author,
        published=published
    )
    return NEXT_ID


async def update_book(
        book_id: int,
        author: str,
        title: str,
        published: datetime
) -> None:
    """Update a book

    Args:
        book_id (int): The id of the book to update
        author (str): The new author
        title (str): The title
        published (datetime): The publication date

    Raises:
        RestError: 404, when a book is not found
    """
    if book_id not in BOOKS:
        raise RestError(404, "Book not found")
    BOOKS[book_id]['title'] = title
    BOOKS[book_id]['author'] = author
    BOOKS[book_id]['published'] = published

We can see that errors are handler by raising ResetError. A convention has been applied such that the status code MUST appear before the message, separated by a comma.

Adding support for the REST router

Now we must create our application and add support for the router.

from bareasgi import Application
from bareasgi_rest import RestHttpRouter, add_swagger_ui


router = RestHttpRouter(
    None,
    title="Books",
    version="1",
    description="A book api",
    base_path='/api/1',
    tags=[
        {
            'name': 'Books',
            'description': 'The book store API'
        }
    ]
)
app = Application(http_router=router)
add_swagger_ui(app)

Note the base_path argument can be used to prefix all paths.

The RestHttpRouter is a subclass of the basic router, so all those methods are also available.

Creating the routes

Now we can create the routes:

tags = ['Books']
router.add_rest({'GET'}, '/books', get_books,tags=tags)
router.add_rest({'GET'}, '/books/{bookId:int}', get_book, tags=tags)
router.add_rest({'POST'}, '/books', create_book, tags=tags, status_code=201)
router.add_rest({'PUT'}, '/books/{bookId:int}', update_book, tags=tags, status_code=204)

First we should note that the paths will be prefixed with the base_path provided to the router.

Referring back to the implementation of get_book we can see that the camel-case path variable bookId has been mapped to the snake-case book_id parameter. The JSON object provided in the body of the create_book will similarly map camel-cased properties to the snake-cased function parameters.

We can also see how the status codes have been overridden for the POST and PUT endpoints, and all the routes have the "Books" tag for grouping in the UI.

Serving the API

Finally we can serve the API:

import uvicorn

uvicorn.run(app, port=9009)

Browsing to http://localhost/api/1/swagger we should see:

Top Level

When we expand GET /books/{bookId} we can see all the information provided in the docstring and typing has been passed through to the swagger UI.

GET /books/{bookId}

Thanks

Thanks to rr- and contributors for the excellent docstring-parser package.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

bareASGI-rest-4.0.1.tar.gz (18.9 kB view details)

Uploaded Source

Built Distribution

bareASGI_rest-4.0.1-py3-none-any.whl (22.6 kB view details)

Uploaded Python 3

File details

Details for the file bareASGI-rest-4.0.1.tar.gz.

File metadata

  • Download URL: bareASGI-rest-4.0.1.tar.gz
  • Upload date:
  • Size: 18.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.1.12 CPython/3.10.10 Darwin/21.6.0

File hashes

Hashes for bareASGI-rest-4.0.1.tar.gz
Algorithm Hash digest
SHA256 1a5c3cecf0a1db9ad88ecf6551e9682cc23e8737d3bb9aeebb922e91b080e574
MD5 7f5734a9a3e445c65bfe366ccd7f26ea
BLAKE2b-256 35176a5e0ae4cd774c9ce21cb3013f029a55d4b6240b8e208c86fe7875e214a4

See more details on using hashes here.

File details

Details for the file bareASGI_rest-4.0.1-py3-none-any.whl.

File metadata

  • Download URL: bareASGI_rest-4.0.1-py3-none-any.whl
  • Upload date:
  • Size: 22.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.1.12 CPython/3.10.10 Darwin/21.6.0

File hashes

Hashes for bareASGI_rest-4.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 7d0b8821238af79cd98c1b79a41bc7d88a3155200af6f3a3bd3820d80f7b8ac0
MD5 6bd2b4d7361dfd51caa06ba6c3ef10e1
BLAKE2b-256 639d28b604ed0b80850c47add6d93eedc766a94c6dbc260901521185324b1396

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page