Skip to content

Repository files navigation

OxAPY

OxAPY is Python HTTP server library build in Rust - a fast, safe and featureementation.

PyPI Downloads

Show your support by giving a star 🌟 if this project helped you!

Features

  • Routing with path parameters
  • Middleware support
  • Static file serving
  • Application state management
  • Request/Response handling
  • Query string parsing
  • Router base path prefixing

Basic Example

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()

Async Example

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())

Middleware

OxAPY offers two paradigms for organizing middleware. You can use one or combine both.

1. Sequence Paradigm (same router)

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_page

2. Multi-Router Paradigm (separate routers)

Each 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])
)

3. Combined (both paradigms)

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
)

Static Files

fromoxapyimportOxapy, Router, static_filedefmain():
(
Oxapy(("127.0.0.1", 5555))
.attach(
Router().route(static_file("/static", "./static"))
)
.run()
)
if__name__=="__main__":
main()

Application State

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()

Router with Base Path

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/users

Todo:

  • 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

About

OxAPY is python HTTP server library build in Rust

Topics

Resources

Stars

10 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages