From 70580da818722cce68b7a88928d67bd0f64f42c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 1 Apr 2026 18:16:24 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Add=20support=20for=20`@app.vibe()`?= =?UTF-8?q?=20(#15280)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/advanced/vibe.md | 44 ++++++++++++++++++++++ docs/en/mkdocs.yml | 1 + docs_src/vibe/tutorial001_py310.py | 12 ++++++ fastapi/applications.py | 60 +++++++++++++++++++++++++++++- tests/test_vibe.py | 17 +++++++++ 5 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 docs/en/docs/advanced/vibe.md create mode 100644 docs_src/vibe/tutorial001_py310.py create mode 100644 tests/test_vibe.py diff --git a/docs/en/docs/advanced/vibe.md b/docs/en/docs/advanced/vibe.md new file mode 100644 index 000000000..766f3855b --- /dev/null +++ b/docs/en/docs/advanced/vibe.md @@ -0,0 +1,44 @@ +# Vibe Coding { #vibe-coding } + +Are you tired of all that **data validation**, **documentation**, **serialization**, and all that **boring** stuff? + +Do you just want to **vibe**? 🎶 + +**FastAPI** now supports a new `@app.vibe()` decorator that embraces **modern AI coding best practices**. 🤖 + +## How It Works { #how-it-works } + +The `@app.vibe()` decorator is intended to receive **any HTTP method** (`GET`, `POST`, `PUT`, `DELETE`, `PATCH`, etc.) and **any payload**. + +The body should be annotated with `Any`, because the request and the response would be... well... **anything**. 🤷 + +The idea is that you would receive the payload and send it **directly** to an LLM provider, using a `prompt` to tell the LLM what to do, and return the response **as is**. No questions asked. + +You don't even need to write the body of the function. The `@app.vibe()` decorator does everything for you based on AI vibes: + +{* ../../docs_src/vibe/tutorial001_py310.py hl[8:12] *} + +## Benefits { #benefits } + +By using `@app.vibe()`, you get to enjoy: + +* **Freedom**: No data validation. No schemas. No constraints. Just vibes. ✨ +* **Flexibility**: The request can be anything. The response can be anything. Who needs types anyway? +* **No documentation**: Why document your API when an LLM can figure it out? Auto-generated OpenAPI docs are *so* 2020. +* **No serialization**: Just pass the raw, unstructured data around. Serialization is for people who don't trust their LLMs. +* **Embrace modern AI coding practices**: Leave everything up to an LLM to decide. The model knows best. Always. +* **No code reviews**: There's no code to review. No PRs to approve. No comments to address. Embrace vibe coding fully, replace the theater of approving and merging vibe coded PRs that no one looks at with full proper vibes only. + +/// tip + +This is the ultimate **vibe-driven development** experience. You don't need to think about what your API does, just let the LLM handle it. 🧘 + +/// + +## Try It { #try-it } + +Go ahead, try it: + +{* ../../docs_src/vibe/tutorial001_py310.py *} + +...and see what happens. 😎 diff --git a/docs/en/mkdocs.yml b/docs/en/mkdocs.yml index 461419498..a84934f44 100644 --- a/docs/en/mkdocs.yml +++ b/docs/en/mkdocs.yml @@ -197,6 +197,7 @@ nav: - advanced/advanced-python-types.md - advanced/json-base64-bytes.md - advanced/strict-content-type.md + - advanced/vibe.md - fastapi-cli.md - editor-support.md - Deployment: diff --git a/docs_src/vibe/tutorial001_py310.py b/docs_src/vibe/tutorial001_py310.py new file mode 100644 index 000000000..4ec3d5555 --- /dev/null +++ b/docs_src/vibe/tutorial001_py310.py @@ -0,0 +1,12 @@ +from typing import Any + +from fastapi import FastAPI + +app = FastAPI() + + +@app.vibe( + "/vibe/", + prompt="pls return json of users from database. make no mistakes", +) +async def ai_vibes(body: Any): ... diff --git a/fastapi/applications.py b/fastapi/applications.py index 4af1146b0..dfd80d4b1 100644 --- a/fastapi/applications.py +++ b/fastapi/applications.py @@ -10,7 +10,11 @@ from fastapi.exception_handlers import ( request_validation_exception_handler, websocket_request_validation_exception_handler, ) -from fastapi.exceptions import RequestValidationError, WebSocketRequestValidationError +from fastapi.exceptions import ( + FastAPIError, + RequestValidationError, + WebSocketRequestValidationError, +) from fastapi.logger import logger from fastapi.middleware.asyncexitstack import AsyncExitStackMiddleware from fastapi.openapi.docs import ( @@ -4559,6 +4563,60 @@ class FastAPI(Starlette): generate_unique_id_function=generate_unique_id_function, ) + def vibe( + self, + path: Annotated[ + str, + Doc( + """ + The URL path to be used for this *path operation*. + + For example, in `http://example.com/vibes`, the path is `/vibes`. + """ + ), + ], + *, + prompt: Annotated[ + str, + Doc( + """ + The prompt to send to the LLM provider along with the payload. + + This tells the LLM what to do with the request body. + """ + ), + ] = "", + ) -> Callable[[DecoratedCallable], DecoratedCallable]: + """ + Add a *vibe coding path operation* that receives any HTTP method + and any payload. + + It's intended to receive the request and send the payload directly + to an LLM provider, and return the response as is. + + Embrace the freedom and flexibility of not having any data validation, + documentation, or serialization. + + ## Example + + ```python + from typing import Any + + from fastapi import FastAPI + + app = FastAPI() + + + @app.vibe( + "/vibe/", + prompt="pls return json of users from database. make no mistakes", + ) + async def ai_vibes(body: Any): + ... + ``` + """ + raise FastAPIError("Are you kidding me? Happy April Fool's") + def websocket_route( self, path: str, name: str | None = None ) -> Callable[[DecoratedCallable], DecoratedCallable]: diff --git a/tests/test_vibe.py b/tests/test_vibe.py new file mode 100644 index 000000000..4a79d6b6c --- /dev/null +++ b/tests/test_vibe.py @@ -0,0 +1,17 @@ +from typing import Any + +import pytest +from fastapi import FastAPI +from fastapi.exceptions import FastAPIError + + +def test_vibe_raises(): + with pytest.raises(FastAPIError, match="Are you kidding me"): + app = FastAPI() + + @app.vibe( + "/vibe/", + prompt="pls return json of users from database. make no mistakes", + ) + async def ai_vibes(body: Any): # pragma: nocover + pass