REST API Generator¶
BESSER offers a code generator for REST API utilizing the FastAPI framework. This tool automatically transforms classes and relationships defined in a Structural model into a RESTful service.
Let’s generate the code for the REST model of our Structural model example structural model example.
You should create a RESTAPIGenerator object, provide the Structural model, and use the generate method as follows:
from besser.generators.rest_api import RESTAPIGenerator
rest_api = RESTAPIGenerator(model=library_model, http_methods=["GET", "POST", "PUT", "PATCH", "DELETE"], backend=False)
rest_api.generate()
Parameters¶
model: The input B-UML structural model (required).http_methods: List of HTTP methods to generate (default:["GET", "POST", "PUT", "PATCH", "DELETE"]).backend: WhenTrue, generates the modular FastAPI application layer used by the BackendGenerator instead of the standalonerest_api.py(default:False).port: Port number embedded in the generated FastAPI app’suvicorn.runcall (optional, default 8000).output_dir: Output directory (default:output/in the current directory).
Note
REST API vs. Backend Generator: The REST API generator produces the API layer only. The Backend generator builds on top of this by also generating the SQLAlchemy ORM models and Pydantic validation models the API imports. Use the REST API generator when you only need API scaffolding; use the Backend generator when you need a complete backend with database.
See also
Need endpoints the model does not describe, or auth on top of them? The Spec-Driven Agent runs this generator (or the Backend generator) first, then lets an LLM customise the result to a natural-language request.
Output Files¶
With backend=False (the default), the generator creates two files in the output directory:
rest_api.py: FastAPI application with CRUD endpoints for each class.pydantic_classes.py: Pydantic validation models generated by the Pydantic generator.
With backend=True, it renders the modular application layer instead (shared with the
Backend generator, which is the usual entry point):
main_api.py: slim app setup that wires in one router per class (run it withuvicorn main_api:app).routers/<class>.py: one router module per class with all of its endpoints.database.py: shared engine/session setup honoring theDATABASE_URLenvironment variable.bal_stdlib.py: B-UML Action Language helpers shared by the routers.requirements.txt: dependencies of the generated application.
The sql_alchemy.py and pydantic_classes.py modules that main_api.py imports are not
generated in this mode — they remain the caller’s responsibility, as the Backend generator demonstrates.
The generated output for the library example is shown below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 | |
When you run the code generated, the OpenAPI specifications will be generated:
{
"openapi": "3.1.0",
"info": {
"title": "FastAPI",
"version": "0.1.0"
},
"paths": {
"/author/": {
"get": {
"tags": [
"author"
],
"summary": "Get Author",
"operationId": "get_author_author__get",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"items": {
"$ref": "#/components/schemas/Author"
},
"type": "array",
"title": "Response Get Author Author Get"
}}}}}}}}}
Note
The full OpenAPI specification is available at http://localhost:8000/docs
when you run the generated FastAPI application with uvicorn rest_api:app.
Association classes¶
When a binary association carries an association class (e.g. Booking — Room
through ReservedRoom with attributes agreed_price and additional_charges),
the generated API manages the link through the association class instead of a plain
join table:
The Create/Update payload of each navigable end carries link objects instead of bare ids:
"rooms": [{"target": 101, "agreed_price": 95.0, "additional_charges": 5.0}](targetis the primary key of the linked entity; plain ids are still accepted, in which case the association attributes are left unset). To-one ends through an association class are optional at creation time — the link can be established later from the other side or via the association class’s own endpoint.PUTreconciles links: removed targets delete the association row, new targets create one, and kept targets have their association attributes updated.GET ...?detailed=trueadditionally returns<end>_linkswith the full association rows.The association class gets its own endpoints; its Create model carries one id field per association end plus the association attributes, and single-item routes are keyed by both foreign keys.
Primary keys are respected everywhere: a class whose id attribute is not named
id(e.g.Room.number) is queried by its actual primary key.