中文 | English
tRPC-FastAPI
tRPC-FastAPI is a FastAPI integration plugin for the tRPC-Python framework (trpc_sdk). It provides HTTP serving out of the box, so you can develop, debug, deploy, and call HTTP APIs quickly. FastAPI is used as the server, so this plugin supports the server side only. Any HTTP client can call it.
Features
- FastAPI integration:
- Drop-in fit: Integrates with the tRPC-Python framework and keeps every tRPC feature;
- HTTP routing: Supports every HTTP method (GET, POST, PUT, DELETE, HEAD, OPTIONS, and others);
- Generated docs: Generates OpenAPI/Swagger docs, including interactive API testing;
- Type safety: Full type-annotation support for a better development experience;
- Development tools:
- Static files: Serves static assets such as HTML, CSS, JS, and images;
- Templates: Integrates the Jinja2 template engine for dynamic page rendering;
- Version info: Reads and displays the FastAPI and plugin versions;
- Deployment:
- Containers: Supports Docker;
- Cloud native: Supports Kubernetes and other cloud-native environments;
Installation
Requirements
- Python 3.8+
- Linux / macOS (tRPC-Python does not support Windows)
- tRPC-Python-SDK
Install
tRPC-Python is currently pinned as a git dependency to the commit referenced above, and pip installs it together with the plugin:
pip install -e .
# To install the extra that includes static templates:
# pip install -e ".[static]"
Quick start
Basic usage
This assumes you already have a generated tRPC project. For the full walkthrough and the one-command run, see examples/README.md. The main files are:
examples/
├── normal_http/
├── http_sse_service.py
├── http_websocket_service.py
├── trpc_main.py
├── run_examples.sh
├── trpc_python.yaml # one process, one uvicorn
├── trpc_python_merge_threads.yaml # one process, multiple handler threads
├── trpc_python_separate_thread.yaml # one process, I/O and handlers split
└── trpc_python_separate.yaml # multi-process separate
1. Register HTTP routes
You can register routes in a separate file. The example below is http_service.py:
from trpc_fastapi import fastapi_route
@fastapi_route("/fastapi_http", ["GET", "HEAD"], route_params={'response_model': dict})
async def fastapi_http(request: Request) -> dict:
"""Test fastapi_http http"""
logger.debug(f"=== normal_http, http_req header: {request.headers} ===")
ctx = get_trpc_ctx()
msg = ctx.get_client_message()
register_service_name = "trpc.trpc_python_group.helloworld.Greeter1"
msg_info = f"\n\n test_route, register service_name: {register_service_name}"
msg_info = f"{msg_info}, callee_service_name: {msg.callee_service_name}\n\n"
logger.debug(f"=== normal_http, msg_info: {msg_info} ===")
return {"message": "This fastapi_http for [GET, HEAD]"}
2. RPC-style HTTP service
Code generated by the stub tool includes protobuf objects. Point it at http_fastapi and it is reachable as-is. Calling through the stub looks like this. Full source: test_service_rpc:
from trpc_sdk.abc import TrpcContext
from trpc_sdk.client import Options
from trpc_sdk.serialization import SerializationType
async def test_sync_Greeter_SayHello():
"""Test Greeter of SayHello"""
proxy = rpc.GreeterClientProxyImpl()
req = pb.HelloRequest()
req.msg = "[sync] Hi SayHello"
options = (Options().set_target('ip://127.0.0.1:8000').set_protocol('http').set_serialization_type(
SerializationType.PB).set_network('tcp').set_short_conn(True))
ctx = TrpcContext()
try:
ret = await proxy.asyncSayHello(ctx, req, options)
print(f"SayHello ret is {ret}")
assert ret is not None
except Exception as exc: # pylint: disable=broad-exception-caught
print(f"error {exc}")
assert 0
curl:
curl -X POST http://127.0.0.1:8000/trpc.trpc_python_group.helloworld.Greeter/SayHello \
-H 'Content-Type: application/json' -d '{"msg":"data"}'
Import the route-registration module in trpc_main.py. The import must happen before create_server:
# Importing registers the plugin, so this has to come first.
import trpc_fastapi as _
# Import the registered HTTP service.
import normal_http as _
To serve another protocol name through FastAPI (for example the a2a plugin), call register_protocol_to_fastapi at import time. This also has to happen before create_server:
from trpc_fastapi import register_protocol_to_fastapi
register_protocol_to_fastapi("a2a")
3. Configuration
See trpc_python.yaml. When global.processmodel is omitted, the server is a single process with one event loop, and uvicorn runs on one thread of the service process.
server:
service:
- name: trpc.trpc_python_group.helloworld.FastApiGreeter
ip: 0.0.0.0
port: 8000
network: tcp
protocol: http_fastapi
Process models
| Config | global.processmodel |
uvicorn |
|---|---|---|
| trpc_python.yaml | omitted | one for the whole service |
| trpc_python_merge_threads.yaml | single_process, handle_num: 2 |
one, started on serving thread 0 |
| trpc_python_separate_thread.yaml | single_process, io_handle_type: separate |
one, started on serving thread 0 |
| trpc_python_separate.yaml | multi_process, io_handle_type: separate, handle_num: 2 |
one per rpc task, listening on 8000 with SO_REUSEPORT. The I/O process listens only on the tRPC port |
Multi-process separate snippet:
global:
processmodel:
mode: multi_process
io_handle_type: separate
handle_num: 2
4. Start the server
In trpc_main.py, import the module that registers routes, such as http_service.py above.
cd examples
./run_examples.sh
# or start it by hand
python3 trpc_main.py --conf trpc_python.yaml
python3 trpc_main.py --conf trpc_python_separate.yaml
5. Call the service
-
In a browser: http://{IP}:{Port}/docs (
IPandPortcome from the config file. If the address is0.0.0.0, use the IP of your environment.) -
With curl:
curl -X GET http://127.0.0.1:8000/details -v
Advanced features
SSE
-
Server code: http_sse_service
import asyncio from fastapi.responses import StreamingResponse from trpc_fastapi import fastapi_route async def event_generator(): """ Simulate async events and push one message every second. """ counter = 0 while True: counter += 1 # SSE format: data: <message>\n\n yield f"data: 这是第 {counter} 条消息\n\n" await asyncio.sleep(1) @fastapi_route('/sse', ["GET"]) async def sse_endpoint(): """ SSE endpoint. Returns the event stream. """ return StreamingResponse(event_generator(), media_type='text/event-stream')
-
Import it in trpc_main.py:
import http_sse_service as _
-
Client check:
curl -X GET http://127.0.0.1:8000/sse -v
WebSocket
-
Server code: http_websocket_service
from fastapi import WebSocket from fastapi.responses import HTMLResponse from trpc_sdk.log import logger from trpc_fastapi import fastapi_route @fastapi_route("/ws", method="WEBSOCKET") async def websocket_endpoint(websocket: WebSocket): await websocket.accept() try: while True: data = await websocket.receive_text() await websocket.send_text(f"Message text was: {data}") except Exception as e: # pylint: disable=broad-except logger.error(f"websocket error: {e}")
-
Import it in trpc_main.py:
import http_websocket_service as _
-
Client check:
python3 examples/client/test_websocket_client.py
Static files
See static_http_service.
-
Install
Static pages may need template rendering. This install is the one to use:
pip install -e ".[static]"
-
Register the static directory
from trpc_fastapi import fastapi_register_static # Directory of static files. static_dir = Path(__file__).parent / "static" # Files used by template rendering. templates_dir = Path(__file__).parent / "templates" fastapi_register_static("/static", static_dir)
-
Register the static route
from trpc_fastapi import fastapi_register_get, trpc_fastapi_version, get_fastapi_app @fastapi_register_get("/", route_params={'response_class': HTMLResponse}) async def static_page(request: Request): """Root path. Returns an HTML page.""" return templates.TemplateResponse( request, "static_page.html", { "trpc_fastapi_version": trpc_fastapi_version, "fastapi_version": fastapi_version, "endpoints": get_all_endpoints() })
Call
get_fastapi_app()inside anasync defroute. FastAPI runs synchronous routes in a thread pool, where the app bound to the current uvicorn thread is not available. -
In a browser: http://{IP}:{Port}/ (
IPandPortcome from the config file. If the address is0.0.0.0, use the IP of your environment.)
Development setup
# After cloning, enter the project directory and install dev dependencies.
pip install -e ".[all]"
# Run tests
pytest tests
# Format the code
./format.sh
Commit conventions
feat:for a new featurefix:for a bug fixdocs:for a documentation update
License
This project is licensed under the Apache-2.0 License. See the LICENSE file.
Metadata
Release files for trpc-fastapi-python 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| trpc_fastapi_python-1.0.0.tar.gz | 69.5 kB | Without provenance | Details for trpc_fastapi_python-1.0.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| trpc_fastapi_python-1.0.0-py3-none-any.whl | Python 3 | none | any | Details for trpc_fastapi_python-1.0.0-py3-none-any.whl |
Total release size: 78.8 kB
Release files / trpc_fastapi_python-1.0.0.tar.gz
| Download URL | trpc_fastapi_python-1.0.0.tar.gz |
|---|---|
| Size | 69.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
144f26fb3a81f9ab08510f2b609aad122b34f99f8eecac2ba634d1f4f433f903
|
|
BLAKE2b-256 checksum How to use checksums |
b94479824448f15d1082073e6fbb247784365f53fa0df704d2ddc2c920bd4bfb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.13
|
Release files / trpc_fastapi_python-1.0.0-py3-none-any.whl
| Download URL | trpc_fastapi_python-1.0.0-py3-none-any.whl |
|---|---|
| Size | 9.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
dd234e640d0b19e78f037a8f8349c9abc5b717a9c5e212291883ab4f723c80fa
|
|
BLAKE2b-256 checksum How to use checksums |
a813085a261a82ef18157aae58886aad50e30a69be0550324d142230206ac014
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.13
|
Security for trpc-fastapi-python 1.0.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.