diff --git a/README.md b/README.md index fab5f716..35b21013 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,6 @@ This package includes a number of utilities to help reduce boilerplate and reuse * **Resource Class**: Create CRUD with ease the OOP way with `Resource` base class that lets you implement methods quick. * **Class Based Views**: Stop repeating the same dependencies over and over in the signature of related endpoints. -* **Response-Model Inferring Router**: Let FastAPI infer the `response_model` to use based on your return type annotation. * **Repeated Tasks**: Easily trigger periodic tasks on server startup * **Timing Middleware**: Log basic timing information for every request * **OpenAPI Spec Simplification**: Simplify your OpenAPI Operation IDs for cleaner output from OpenAPI Generator diff --git a/docs/src/class_based_views2.py b/docs/src/class_based_views2.py index b81e3ed1..2320691f 100644 --- a/docs/src/class_based_views2.py +++ b/docs/src/class_based_views2.py @@ -2,14 +2,13 @@ from uuid import UUID import sqlalchemy as sa -from fastapi import Depends, FastAPI, Header, HTTPException +from fastapi import Depends, FastAPI, Header, HTTPException, APIRouter from sqlalchemy.orm import Session, declarative_base from starlette.status import HTTP_403_FORBIDDEN, HTTP_404_NOT_FOUND from fastapi_restful.api_model import APIMessage, APIModel from fastapi_restful.cbv import cbv from fastapi_restful.guid_type import GUID -from fastapi_restful.inferring_router import InferringRouter # Begin Setup UserID = NewType("UserID", UUID) @@ -54,7 +53,7 @@ def get_owned_item(session: Session, owner: UserID, item_id: ItemID) -> ItemORM: # End Setup app = FastAPI() -router = InferringRouter() # Step 1: Create a router +router = APIRouter() # Step 1: Create a router @cbv(router) # Step 2: Create and decorate a class to hold the endpoints diff --git a/docs/src/inferring_router2.py b/docs/src/inferring_router2.py deleted file mode 100644 index 94b09345..00000000 --- a/docs/src/inferring_router2.py +++ /dev/null @@ -1,33 +0,0 @@ -from fastapi import FastAPI - -from fastapi_restful.inferring_router import InferringRouter - -app = FastAPI() - - -@app.get("/default") -def get_resource(resource_id: int) -> str: - # the response will be serialized as a JSON number, *not* a string - return resource_id - - -router = InferringRouter() - - -@router.get("/inferred") -def get_resource(resource_id: int) -> str: - # thanks to InferringRouter, the response will be serialized as a string - return resource_id - - -app.include_router(router) - - -def get_response_schema(openapi_spec, endpoint_path): - responses = openapi_spec["paths"][endpoint_path]["get"]["responses"] - return responses["200"]["content"]["application/json"]["schema"] - - -openapi_spec = app.openapi() -assert get_response_schema(openapi_spec, "/default") == {} -assert get_response_schema(openapi_spec, "/inferred")["type"] == "string" diff --git a/docs/user-guide/inferring-router.md b/docs/user-guide/inferring-router.md deleted file mode 100644 index 9693c980..00000000 --- a/docs/user-guide/inferring-router.md +++ /dev/null @@ -1,47 +0,0 @@ -#### Source module: [`fastapi_restful.inferring_router`](https://github.com/yuval9313/fastapi-restful/blob/master/fastapi_restful/inferring_router.py){.internal-link target=_blank} - ---- - -## Using `response_model` -One of the few places where FastAPI can't always infer everything you might want it to -purely from type hints is the `response_model` to use for a specific endpoint. - -```python hl_lines="7 18" -{!./src/inferring_router1.py!} -``` - -The reason for this is that you may want to return an object of a *different type* than the endpoint's -`response_model`, but still have it serialized as though it were an instance of the `response_model`. - -Even when the returned object *and* the `response_model` are pydantic models, specifying a `response_model` -ensures that no extra nested attributes will be included. This could be important for security -reasons if the returned object has sensitive fields you don't want to include in the response. - -However, this can result in surprising errors where you refactor an endpoint to return a different model, -but forget to change the specified `response_model`, and FastAPI serializes (or attempts to serialize) the -response as an undesired type. - -## Inferring `response_model` - -If you know that you want to use the annotated return type as the `response_model` (for serialization -purposes *or* for OpenAPI spec generation), you can use a `fastapi_restful.inferring_router.InferringRouter` -in place of an `APIRouter`, and the `response_model` will be automatically extracted from the annotated -return type. - -As you can see below, by default, no response schema is generated when you don't specify a `response_model`: -```python hl_lines="6 18" -{!./src/inferring_router1.py!} -``` - -However, using `InferringRouter`, a response schema *is* generated by default: - -```python hl_lines="3 14 17 23 33" -{!./src/inferring_router2.py!} -``` - -Behind the scenes, what happens is precisely equivalent to what would happen if you passed the annotated return type -as the `response_model` argument to the endpoint decorator. So the annotated return type will also be used -for serialization, etc. - -Note that `InferringRouter` has precisely the same API for all methods as a regular `APIRouter`, and you can still -manually override the provided `response_model` if desired. diff --git a/mkdocs.yml b/mkdocs.yml index e4b2a585..539cd64e 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -18,7 +18,6 @@ nav: - User Guide: - Class Resource: 'user-guide/class-resource.md' - Class Based Views: 'user-guide/class-based-views.md' - - Inferring Router: 'user-guide/inferring-router.md' - Repeated Tasks: 'user-guide/repeated-tasks.md' - Timing Middleware: 'user-guide/timing-middleware.md' - SQLAlchemy Sessions: 'user-guide/session.md'