Skip to content

Commit

Permalink
feat: adds Flask extension that dynamically generates OpenAPI specifi…
Browse files Browse the repository at this point in the history
…cation and Swagger UI. (#44)
  • Loading branch information
dtiesling committed Jan 28, 2024
1 parent 26d5766 commit 2bc465e
Show file tree
Hide file tree
Showing 17 changed files with 2,381 additions and 699 deletions.
20 changes: 16 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,9 @@ Flask-Muck is a batteries-included declarative framework for automatically gener
Update and Delete (CRUD) endpoints in a Flask/SqlAlchemy application stack in as little as 9 lines of code.



```python
from flask import Blueprint
from flask_muck.views import FlaskMuckApiView
from flask import Blueprint, Flask
from flask_muck.views import FlaskMuckApiView, FlaskMuck
import marshmallow as ma
from marshmallow import fields as mf

Expand Down Expand Up @@ -51,10 +50,21 @@ class MyModelApiView(FlaskMuckApiView):
searchable_columns = [MyModel.name]


app = Flask(__name__)

# Initialize the FlaskMuck extension if you want all batteries included.
# Using the extension will autogenerate a Swagger UI browsable api documentation at /apidocs/
app.config['MUCK_API_URL_PREFIX'] = "/api/"
muck = FlaskMuck()
muck.init_app(app)
muck.register_muck_views([MyModelApiView])

# OR add CRUD views to an existing Flask Blueprint for greater flexibility
blueprint = Blueprint("api", __name__, url_prefix="/api/")
MyModelApiView.add_rules_to_blueprint(blueprint)

# Available Endpoints:

# Either option generates the following endpoints:
# CREATE | curl -X POST "/api/v1/my-model" -H "Content-Type: application/json" \-d "{\"name\": \"Ayla\"}"
# LIST ALL | curl -X GET "/api/v1/my-model" -d "Accept: application/json"
# LIST ALL PAGINATED | curl -X GET "/api/v1/my-model?limit=100&offset=50" -d "Accept: application/json"
Expand All @@ -68,12 +78,14 @@ MyModelApiView.add_rules_to_blueprint(blueprint)
```

## Features

- Uses a declarative and modular approach to automatically generate CRUD endpoints.
- Built-in search, filter, sort and pagination when listing resources.
- Support for APIs with nested resources (i.e. /api/classrooms/12345/students).
- Fully compatible with any other Flask method-based or class-based views. Mix & match with your existing views.
- Pre and post callbacks configurable on all manipulation endpoints. Allow for adding arbitrary logic before and after Create, Update or Delete operations.
- Supports Marshmallow and Pydantic for schema definitions.
- Dynamically generates OpenAPI specification and Swagger UI.

## Documentation

Expand Down
40 changes: 29 additions & 11 deletions docs/docs/configuration.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,40 @@
# Configuration

Configuration in Flask-Muck is handled entirely through setting class variables on `FlaskMuckApiView`. As noted in the [quickstart](quickstart.md), you will likely have some class variable settings that are shared by most or all of your view classes. It's advisable to set up base classes to handle sharing configuration between views.
Configuration in Flask-Muck is handled at the app-level and class-level.

## App-Level Configuration

When using the `FlaskMuck` extension the following settings can be configured using the standard Flask config API.

| Key | Default | Description |
|--------------------------|------------|--------------------------------------------------------------------------------------------------|
| MUCK_API_URL_PREFIX | "/" | URL prefix the CRUD views will be registered under. |
| MUCK_APIDOCS_ENABLED | True | If True, Swagger UI browser API docs will be available. |
| MUCK_APIDOCS_URL_PATH | "/apidocs/ | URL path to register the browsable API docs. |
| MUCK_API_VERSION | 1.0.0 | API version. Used in OpenAPI spec definition and Swagger UI. |
| MUCK_API_TITLE | "REST API" | Title of the API. Used in OpenAPI spec definition and Swagger UI. |
| MUCK_APIDOCS_INTERACTIVE | False | If True, Swagger UI wil have interactive mode enable allowing users to make requests to the API. |

## FlaskMuckApiView Class Variables

Much of the configuration occurs through setting class variables on `FlaskMuckApiView` classes. As noted in
the [quickstart](quickstart.md), you will
likely have some class variable settings that are shared by most or all of your view classes. It's advisable to set up
base classes to handle sharing configuration between views.

| Class Variable | Description | Required |
|:------------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| :------------------------: |
|:------------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------------------------:|
| session `scoped_session` | SqlAlchemy database session used to query and modify the resource. | :octicons-check-circle-16: |
| api_name `str` | Name of the API. Used as the url path appended to your Flask Blueprint. | :octicons-check-circle-16: |
| Model `SqlaModelType` | SqlAlchemy Model used to make queries. | :octicons-check-circle-16: |
| ResponseSchema `SerializerType` | Marshmallow schema or Pydantic model used to serialize the resource returned by any of the views. | :octicons-check-circle-16: |
| ResponseSchema `SerializerType` | Marshmallow schema or Pydantic model used to serialize the resource returned by any of the views. | :octicons-check-circle-16: |
| decorators `list[Callable]` | List of decorators to apply to all views in the API. This is inherited functionality built into Flask's [class-based views](https://flask.palletsprojects.com/en/2.3.x/views/#view-decorators). | |
| parent `Optional[type[FlaskMuckApiView]]` | If set, this API becomes a nested resource API. For more information on nested APIs see the [documentation](nesting_apis.md). | |
| CreateSchema `Optional[SerializerType]]` | Marshmallow schema or Pydantic model used to validate the POST request JSON payload sent to create a resource. | |
| UpdateSchema `Optional[SerializerType]]` | Marshmallow schema or Pydantic model used to validate the PUT request JSON payload sent to update a resource. | |
| PatchSchema `Optional[SerializerType]]` | Marshmallow schema or Pydantic model used to validate the PATCH request JSON payload sent to patch a resource. | |
| DeleteSchema `Optional[SerializerType]]` | Marshmallow schema or Pydantic model used to validate the DELETE request JSON payload sent to create a resource. Optional. | |
| DetailSchema `Optional[SerializerType]]` | Optional Marshmallow schema or Pydantic model used to serialize the resource returned by the GET /<api_name\>/<ID\>/ endpoint. If this schema is not set the ResponseSchema is used. | |
| CreateSchema `Optional[SerializerType]]` | Marshmallow schema or Pydantic model used to validate the POST request JSON payload sent to create a resource. | |
| UpdateSchema `Optional[SerializerType]]` | Marshmallow schema or Pydantic model used to validate the PUT request JSON payload sent to update a resource. | |
| PatchSchema `Optional[SerializerType]]` | Marshmallow schema or Pydantic model used to validate the PATCH request JSON payload sent to patch a resource. | |
| DeleteSchema `Optional[SerializerType]]` | Marshmallow schema or Pydantic model used to validate the DELETE request JSON payload sent to create a resource. Optional. | |
| DetailSchema `Optional[SerializerType]]` | Optional Marshmallow schema or Pydantic model used to serialize the resource returned by the GET /<api_name\>/<ID\>/ endpoint. If this schema is not set the ResponseSchema is used. | |
| pre_create_callbacks `list[type[FlaskMuckCallback]]` | List of callback classes to be called before a resource is created. Ideal for validation. | |
| pre_update_callbacks `list[type[FlaskMuckCallback]]` | List of callback classes to be called before a resource is updated. Ideal for validation. | |
| pre_patch_callbacks `list[type[FlaskMuckCallback]]` | List of callback classes to be called before a resource is patched. Ideal for validation. | |
Expand All @@ -31,7 +49,7 @@ Configuration in Flask-Muck is handled entirely through setting class variables
| allowed_methods `set[str]` | Set of allowed HTTP methods for this API. Default is `{"GET", "POST", "PUT", "PATCH", "DELETE"}`. This setting is used to control which actions are available for this resource. Not including a method affects which routes will be registered to a Flask Blueprint. | |
| operator_separator `str` | Separator used when assigning operators to search or filter query parameters in the GET /<api_name\>/ endpoint. Default is `"__"`. | |

## Base Class Example
### Base Class Example

Suppose you have an API with the following requirements for all views:

Expand All @@ -52,10 +70,10 @@ class BaseApiView(FlaskMuckApiView):
```

```python title="Concrete Class"
class TurtleApiView(BaseApiView):#(1)!
class TurtleApiView(BaseApiView): # (1)!
api_name = 'turtles'
Model = Turtle
...#(2)!
... # (2)!
```

1. The concrete view inherits from BaseApiView and all of its configurations.
Expand Down
53 changes: 42 additions & 11 deletions docs/docs/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,25 +97,56 @@ class TeacherApiView(BaseApiView):
6. Marshmallow schema used to validate payload data sent to the Update endpoint.
7. List of model columns that can be searched when listing Teachers using the API.

## Add URL Rules to a Flask Blueprint
The final step is to add the correct URL rules to an existing [Flask Blueprint](https://flask.palletsprojects.com/en/3.0.x/blueprints/) object. A class method is included that handles adding all necessary rules to the given Blueprint.
## Register the FlaskMuckApiViews
There are two options for registering the CRUD views. FlaskMuck can be initialized as a Flask extension or each
FlaskMuckApiView can be added to an existing Flask Blueprint.

### Initialize FlaskMuck extension.
The FlaskMuck extension is the "batteries included" approach and handles registering all of your views to a single
API url root. Optionally the extension generates an OpenAPI spec definition and host a Swagger UI page.

```python
from myapp import app

from flask_muck import FlaskMuck

app.config['MUCK_API_URL_PREFIX'] = "/api/"
app.config['MUCK_APIDOCS_ENABLED'] = True
app.config['MUCK_API_TITLE'] = "School App API"
muck = FlaskMuck(app)
muck.register_muck_views([TeacherApiView])
```

### OR

### Manually register FlaskMuckApiViews
Manually registering each FlaskMuckApiView is an escape hatch to allow greater flexibility to work with existing
views in an app and other frameworks and extensions.

A class method is included that handles adding all necessary rules to the given Blueprint.

```python
from flask import Blueprint

from myapp import app

blueprint = Blueprint("api", __name__, url_prefix="/api/")
TeacherApiView.add_rules_to_blueprint(blueprint)
app.register_blueprint(blueprint)
```

This setup produces the following views for a standard REST API:
## Success!

The following views are generated for a standard REST API:

| URL Path | Method | Description |
|--------------------|--------|-----------------------------------------------------------------------------------------------------------|
| /api/teachers/ | GET | List all teachers - querystring options available for sorting, filtering, searching, and pagination |
| /api/teachers/ | POST | Create a teacher |
| /api/teachers/\<ID> | GET | Fetch a single teacher |
| /api/teachers/\<ID> | PUT | Update a single teacher |
| /api/teachers/\<ID> | PATCH | Patch a single teacher |
| /api/teachers/\<ID> | DELETE | Delete a single teacher |
| URL Path | Method | Description |
|-----------------------------|--------|------------------------------------------------------------------------------------------------------------|
| /api/teachers/ | GET | List all teachers - querystring options available for sorting, filtering, searching, and pagination |
| /api/teachers/ | POST | Create a teacher |
| /api/teachers/<TEACHER_ID\> | GET | Fetch a single teacher |
| /api/teachers/<TEACHER_ID\> | PUT | Update a single teacher |
| /api/teachers/<TEACHER_ID\> | PATCH | Patch a single teacher |
| /api/teachers/<TEACHER_ID\> | DELETE | Delete a single teacher |
| /apidocs/ | GET | Swagger UI browsable API documentation page (Only available if FlaskMuck extension used to register views) |


Loading

0 comments on commit 2bc465e

Please sign in to comment.