CBRA (Class-based REStful API)¶
The cbra
(pronounced “zebra”) package is a framework to create REStful
HTTP APIs using a class-based, object-oriented approach. It is implemented
on top of starlette
and fastapi
, and draws inspiration from
Django and Django REST Framework.
Key features¶
Asynchronous: designed from scratch to support asynchronous I/O in Python web applications.
Lightning-speed development: wireframe a REStful web resource by simply subclassing
cbra.core.ResourceModel
.Faster time-to-market: measured in hours, not weeks.
Easy to adopt: built on top of FastAPI and Starlette. If you’re familiar with Django REST Framework, adopting
cbra
is a small step for you, but a giant leap for your project.Built-in support for webhooks and event-driven systems.
All FastAPI benefits plus a class-oriented programming interface.
Installation¶
To install cbra
with Python 3.10+:
pip3 install cbra
Getting started¶
Check out the example below to get an idea of cbra
and its powerful,
yet simple interface. For all examples, head over to the Guides
section to get started!
Define your resource model¶
Implementing a REStful API with cbra
always starts with declaratively
defining your resource model.
import pydantic
from cbra.core import ResourceModel
class Book(ResourceModel):
# Note the 'primary_key' and 'read_only' arguments. The 'primary_key'
# argument specifies that this field identifies the Book. The 'read_only'
# argument indicates that the field may not be set by clients, and
# will not be ignored in POST/PUT/PATCH requests. It is also not included
# in the OpenAPI documentation for these methods.
#
# When constructing URLs for Resource implementations, this field is used
# to construct the URL parameter by lowercasing the resource models' name
# and appending '_id' to it. In this example that would thus be 'book_id'.
id: int | None = pydantic.Field(
default=None,
primary_key=True,
read_only=True
)
title: str
Implementing your resource¶
To implement endpoints for the Book
model you defined, create a
subclass of Resource
and implement just four methods
to have a fully functional, readable and writable RESTful HTTP resource.
import secrets
from cbra.core import Mutable, Resource
class BookResource(Resource, Mutable, model=Book):
books: dict[int, Book] = {
1: Book(id=1, title="The Hitchhiker's Guide to the Galaxy")
}
async def can_create(self, resource: Book) -> bool:
# Hook to determine if an object can be created. The default
# implementation always raises a NotImplementedError. Uniqueness
# check etc. should be performed here.
return not any([
x.title == resource.title
for x in self.books.values()]
)
async def delete(self, resource: Book):
# Delete a resource from your storage backend. For this example we use
# a simple dictionary, but in a real implementation this could be
# a relational database or document storage system.
assert resource.id is not None
self.books.pop(resource.id)
async def get_object(self) -> Book | None:
# Must be implemented to return an instance of Book, or None
# if the Book does not exist. In the latter case, the client
# automatically receives a 404 status code.
return self.books.get(int(self.request.path_params['book_id']))
async def persist(self, resource: Book, create: bool = False) -> Book:
# Persist a resource to your storage backend. Same applies as for
# delete().
if create:
assert resource.id is None
resource.id = secrets.choice(range(1000, 9999))
assert resource.id is not None
self.books[resource.id] = resource
return resource
Serving your REStful HTTP API¶
Exposing BookResource
to HTTP clients then becomes as simple as:
import uvicorn
import cbra.core as cbra
app: cbra.Application = cbra.Application()
app.add(BookResource)
uvicorn.run(app)
Run this code and visit http://localhost:8000/redoc to see the result! ReDoc will properly show the exposed GET, POST, PUT, PATCH and DELETE methods. It’s that simple.