|
2 | 2 | import reflex as rx |
3 | 3 | ``` |
4 | 4 |
|
5 | | -# Backend API Routes |
| 5 | +# API Transformer |
6 | 6 |
|
7 | | -In addition to your frontend app, Reflex also uses a FastAPI backend to serve your app. |
| 7 | +In addition to your frontend app, Reflex uses a FastAPI backend to serve your app. The API transformer feature allows you to transform or extend the ASGI app that serves your Reflex application. |
8 | 8 |
|
9 | | -To add additional endpoints to the backend API, you can use `app.add_api_route` and add a route that returns JSON. |
| 9 | +## Overview |
| 10 | + |
| 11 | +The API transformer provides a way to: |
| 12 | + |
| 13 | +1. Integrate existing FastAPI or Starlette applications with your Reflex app |
| 14 | +2. Apply middleware or transformations to the ASGI app |
| 15 | +3. Extend your Reflex app with additional API endpoints |
| 16 | + |
| 17 | +This is useful for creating a backend API that can be used for purposes beyond your Reflex app, or for integrating Reflex with existing backend services. |
| 18 | + |
| 19 | +## Using API Transformer |
| 20 | + |
| 21 | +You can set the `api_transformer` parameter when initializing your Reflex app: |
10 | 22 |
|
11 | 23 | ```python |
12 | | -async def api_test(item_id: int): |
13 | | - return \{"my_result": item_id} |
| 24 | +import reflex as rx |
| 25 | +from fastapi import FastAPI, Depends |
| 26 | +from fastapi.security import OAuth2PasswordBearer |
| 27 | + |
| 28 | +# Create a FastAPI app |
| 29 | +fastapi_app = FastAPI(title="My API") |
14 | 30 |
|
15 | | -app = rx.App() |
16 | | -app.api.add_api_route("/items/\{item_id}", api_test) |
| 31 | +# Add routes to the FastAPI app |
| 32 | +@fastapi_app.get("/api/items") |
| 33 | +async def get_items(): |
| 34 | + return dict(items=["Item1", "Item2", "Item3"]) |
| 35 | + |
| 36 | +# Create a Reflex app with the FastAPI app as the API transformer |
| 37 | +app = rx.App(api_transformer=fastapi_app) |
17 | 38 | ``` |
18 | 39 |
|
19 | | -Now you can access the endpoint at `localhost:8000/items/23` and get the result. |
| 40 | +## Types of API Transformers |
| 41 | + |
| 42 | +The `api_transformer` parameter can accept: |
| 43 | + |
| 44 | +1. A Starlette or FastAPI instance |
| 45 | +2. A callable that takes an ASGIApp and returns an ASGIApp |
| 46 | +3. A sequence of the above |
| 47 | + |
| 48 | +### Using a FastAPI or Starlette Instance |
20 | 49 |
|
21 | | -This is useful for creating a backend API that can be used for purposes other than your Reflex app. |
| 50 | +When you provide a FastAPI or Starlette instance as the API transformer, Reflex will mount its internal API to your app, allowing you to define additional routes: |
| 51 | + |
| 52 | +```python |
| 53 | +import reflex as rx |
| 54 | +from fastapi import FastAPI, Depends |
| 55 | +from fastapi.security import OAuth2PasswordBearer |
| 56 | + |
| 57 | +# Create a FastAPI app with authentication |
| 58 | +fastapi_app = FastAPI(title="Secure API") |
| 59 | +oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") |
| 60 | + |
| 61 | +# Add a protected route |
| 62 | +@fastapi_app.get("/api/protected") |
| 63 | +async def protected_route(token: str = Depends(oauth2_scheme)): |
| 64 | + return dict(message="This is a protected endpoint") |
| 65 | + |
| 66 | +# Create a token endpoint |
| 67 | +@fastapi_app.post("/token") |
| 68 | +async def login(username: str, password: str): |
| 69 | + # In a real app, you would validate credentials |
| 70 | + if username == "user" and password == "password": |
| 71 | + return dict(access_token="example_token", token_type="bearer") |
| 72 | + return dict(error="Invalid credentials") |
| 73 | + |
| 74 | +# Create a Reflex app with the FastAPI app as the API transformer |
| 75 | +app = rx.App(api_transformer=fastapi_app) |
| 76 | +``` |
| 77 | + |
| 78 | +### Using a Callable Transformer |
| 79 | + |
| 80 | +You can also provide a callable that transforms the ASGI app: |
| 81 | + |
| 82 | +```python |
| 83 | +import reflex as rx |
| 84 | +from starlette.middleware.cors import CORSMiddleware |
| 85 | + |
| 86 | +# Create a transformer function that returns a transformed ASGI app |
| 87 | +def add_cors_middleware(app): |
| 88 | + # Wrap the app with CORS middleware and return the wrapped app |
| 89 | + return CORSMiddleware( |
| 90 | + app=app, |
| 91 | + allow_origins=["https://example.com"], |
| 92 | + allow_methods=["*"], |
| 93 | + allow_headers=["*"], |
| 94 | + ) |
| 95 | + |
| 96 | +# Create a Reflex app with the transformer |
| 97 | +app = rx.App(api_transformer=add_cors_middleware) |
| 98 | +``` |
| 99 | + |
| 100 | +### Using Multiple Transformers |
| 101 | + |
| 102 | +You can apply multiple transformers by providing a sequence: |
| 103 | + |
| 104 | +```python |
| 105 | +import reflex as rx |
| 106 | +from fastapi import FastAPI |
| 107 | +from starlette.middleware import Middleware |
| 108 | +from starlette.middleware.cors import CORSMiddleware |
| 109 | + |
| 110 | +# Create a FastAPI app |
| 111 | +fastapi_app = FastAPI(title="My API") |
| 112 | + |
| 113 | +# Add routes to the FastAPI app |
| 114 | +@fastapi_app.get("/api/items") |
| 115 | +async def get_items(): |
| 116 | + return dict(items=["Item1", "Item2", "Item3"]) |
| 117 | + |
| 118 | +# Create a transformer function |
| 119 | +def add_logging_middleware(app): |
| 120 | + # This is a simple example middleware that logs requests |
| 121 | + async def middleware(scope, receive, send): |
| 122 | + # Log the request path |
| 123 | + path = scope["path"] |
| 124 | + print("Request:", path) |
| 125 | + await app(scope, receive, send) |
| 126 | + return middleware |
| 127 | + |
| 128 | +# Create a Reflex app with multiple transformers |
| 129 | +app = rx.App(api_transformer=[fastapi_app, add_logging_middleware]) |
| 130 | +``` |
22 | 131 |
|
23 | 132 | ## Reserved Routes |
24 | 133 |
|
25 | 134 | Some routes on the backend are reserved for the runtime of Reflex, and should not be overridden unless you know what you are doing. |
26 | 135 |
|
27 | | -## Ping |
| 136 | +### Ping |
28 | 137 |
|
29 | 138 | `localhost:8000/ping/`: You can use this route to check the health of the backend. |
30 | 139 |
|
31 | 140 | The expected return is `"pong"`. |
32 | 141 |
|
33 | | -## Event |
| 142 | +### Event |
34 | 143 |
|
35 | 144 | `localhost:8000/_event`: the frontend will use this route to notify the backend that an event occurred. |
36 | 145 |
|
37 | 146 | ```md alert error |
38 | 147 | # Overriding this route will break the event communication |
39 | 148 | ``` |
40 | 149 |
|
41 | | -## Upload |
| 150 | +### Upload |
42 | 151 |
|
43 | 152 | `localhost:8000/_upload`: This route is used for the upload of file when using `rx.upload()`. |
0 commit comments