OxAPY is Python HTTP server library build in Rust - a fast, safe and featureementation.
Show your support by giving a star 🌟 if this project helped you!
- Routing with path parameters
- Middleware support
- Static file serving
- Application state management
- Request/Response handling
- Query string parsing
- Router base path prefixing
fromoxapyimportOxapy, Router, Status, Response, get@get("/")defwelcome(request):
returnResponse("Welcome to OxAPY!", content_type="text/plain")
@get("/hello/{name}")defhello(request, name):
returnResponse({"message": f"Hello, {name}!"})
defmain():
(
Oxapy(("127.0.0.1", 5555))
.attach(
Router()
.route(welcome)
.route(hello)
)
.run(reload=True) # False as default
)
if__name__=="__main__":
main()fromoxapyimportOxapy, Router, getimportasyncio@get("/")asyncdefhome(request):
# Asynchronous operations are allowed heredata=awaitfetch_data_from_database() return"Hello, World!"asyncdefmain():
await (
Oxapy(("127.0.0.1", 8000))
.attach(
Router().route(home)
)
.async_mode()
.run()
)
if__name__=="__main__":
asyncio.run(main())OxAPY offers two paradigms for organizing middleware. You can use one or combine both.
Middleware only applies to routes registered after it within the same router. Routes before it get no middleware.
# Simple: one middleware layerRouter()
.route(get("/health", lambda_: "OK")) # no middleware
.middleware(auth)
.route(get("/dashboard", dashboard)) # auth only
.route(get("/account", account)) # auth only# Multiple layers: each middleware applies to everything after itRouter()
.route(get("/health", lambda_: "OK")) # no middleware
.route(static_file()) # no middleware
.middleware(session)
.route(get("/login", login)) # session
.route(get("/register", register)) # session
.middleware(db_session)
.route(get("/search", search)) # session + db_session
.route(get("/profile", profile)) # session + db_session
.middleware(protect_page)
.route(get("/admin", admin)) # session + db_session + protect_pageEach router has its own independent middleware stack. Routers are checked in order until a match is found. Use this when groups share no middleware.
# Simple: two isolated groupsOxapy(("127.0.0.1", 5555))
.attach(
Router()
.route(get("/health", lambda_: "OK"))
.route(static_file())
)
.attach(
Router()
.middleware(auth)
.route(get("/dashboard", dashboard))
.route(get("/account", account))
)# Multiple isolated groups with different middleware stacksOxapy(("127.0.0.1", 5555))
.attach(
Router()
.route(static_file())
.route(get("/health", lambda_: "Good!"))
)
.attach(
Router()
.middleware(session)
.middleware(db_session)
.routes([login_user, register_user, show_login_page])
)
.attach(
Router()
.middleware(session)
.middleware(db_session)
.middleware(protect_page)
.routes([show_dashboard, show_account, logout_user])
)Use sequence layering inside a router alongside separate routers.
Oxapy(("127.0.0.1", 5555))
.attach(
Router()
.route(get("/health", lambda_: "OK")) # no middleware
.middleware(rate_limit)
.route(get("/login", login)) # rate_limit
.route(get("/register", register)) # rate_limit
)
.attach(
Router()
.middleware(session)
.middleware(db_session)
.route(get("/dashboard", dashboard)) # session + db_session
.middleware(protect_page)
.route(get("/admin", admin)) # session + db_session + protect_page
)fromoxapyimportOxapy, Router, static_filedefmain():
(
Oxapy(("127.0.0.1", 5555))
.attach(
Router().route(static_file("/static", "./static"))
)
.run()
)
if__name__=="__main__":
main()fromoxapyimportOxapy, Router, getclassAppState:
def__init__(self):
self.counter=0@get("/count")defhandler(request):
app_data=request.app_dataapp_data.counter+=1return {"count": app_data.counter}
defmain():
(
Oxapy(("127.0.0.1", 5555))
.app_data(AppState())
.attach(
Router().route(handler)
)
.run()
)
if__name__=="__main__":
main()You can set a base path for a router, which will be prepended to all routes defined in it. This is useful for versioning APIs.
fromoxapyimportOxapy, Router, get@get("/users")defget_users(request):
return [{"id": 1, "name": "user1"}]
defmain():
(
Oxapy(("127.0.0.1", 5555))
.attach(
Router("/api/v1").route(get_users)
)
.run()
)
if__name__=="__main__":
main()
# You can now access the endpoint at http://127.0.0.1:5555/api/v1/usersTodo:
- Handler
- HttpResponse
- Routing
- use tokio::net::Listener
- middleware
- app data
- pass request in handler
- serve static file
- templating
- query uri
- security submodule
- jwt
- bcrypt
- websocket
