RFC基準と削除操作のステータスコード
RFC 9110では、特に削除操作(DELETEリクエスト)の場合、レスポンスボディが含まれる場合は200 OK
を使用し、レスポンスボディがない場合は204 No Content
を使用すべきとされています。
a DELETE method is successfully applied, the origin server SHOULD send a 202 (Accepted) status code if the action will likely succeed but has not yet been enacted, a 204 (No Content) status code if the action has been enacted and no further information is to be supplied, or a 200 (OK) status code if the action has been enacted and the response message includes a representation describing the status.
しかし、FastAPIはリクエストが成功した時は、デフォルトで200 OKステータスコードを返すようになっているので、今回は削除が成功した時に204 No Content
を返せるようにしてみます。
Response class - FastAPI
DELETEエンドポイントの設定
reports = { "1": {"title": "Report 1", "description": "This is a report"}, "2": {"title": "Report 2", "description": "This is another report"}, "3": {"title": "Report 3", "description": "This is a third report"} } @app.get("/reports") async def get_reports(): return reports @app.delete("/reports/{report_id}", status_code=204) async def delete_report(report_id: str): if report_id in reports: del reports[report_id] else: raise HTTPException(status_code=404, detail="Item not found")
エンドポイントの設定時に、status_code=204
を指定し、DELETE
が出来ていることを確認するため、GET
も用意しています。
Swagger UIで確認
status code 204
が返ってきました。
実装を確認する
Starlette
# starlette/responses.py class Response: media_type = None charset = "utf-8" def __init__( self, content: typing.Any = None, status_code: int = 200, headers: typing.Optional[typing.Mapping[str, str]] = None, media_type: typing.Optional[str] = None, background: typing.Optional[BackgroundTask] = None, ) -> None: self.status_code = status_code (略)
FastAPI
from starlette.responses import JSONResponse, Response async def app(request: Request) -> Response: try: body: Any = None if body_field: if is_body_form: body = await request.form() stack = request.scope.get("fastapi_astack") assert isinstance(stack, AsyncExitStack) stack.push_async_callback(body.close) else: body_bytes = await request.body() if body_bytes: json_body: Any = Undefined content_type_value = request.headers.get("content-type") if not content_type_value: json_body = await request.json() else: message = email.message.Message() message["content-type"] = content_type_value if message.get_content_maintype() == "application": subtype = message.get_content_subtype() if subtype == "json" or subtype.endswith("+json"): json_body = await request.json() if json_body != Undefined: body = json_body else: body = body_bytes def api_route( self, path: str, *, response_model: Any = Default(None), status_code: Optional[int] = None, (略) ), ) -> Callable[[DecoratedCallable], DecoratedCallable]: def decorator(func: DecoratedCallable) -> DecoratedCallable: self.add_api_route( path, func, response_model=response_model, status_code=status_code, def delete( self, path: str, *, response_model: Any = Default(None), status_code: Optional[int] = None, (略)
FastAPIは、StarletteからResponseクラスをインポートして、Starletteが提供するレスポンスの生成と管理機能にアクセスし、
async def app(request: Request) -> Response
、def delete(...)
で、HTTPリクエストを受け取り、StarletteのResponse型を戻り値として設定して、DELETEレスポンスを返しているようです。