Mastering Starlette A Lightweight ASGI Framework for High Performance Web Applications

Mastering Starlette: A Lightweight ASGI Framework for High-Performance Web Applications

Starlette is a lightweight and fast ASGI framework for building high-performance web applications in Python. Its simplicity and efficiency make it an ideal choice for developers looking to create scalable APIs, real-time services, and microservices. Starlette comes with a rich set of features, including request and response handling, routing, middleware, WebSocket support, and more. Let’s dive into its core concepts and explore some useful APIs through examples.

Understanding Starlette’s Features

Here are some of the key features of Starlette:

  • ASGI-based for asynchronous programming.
  • Support for HTTP and WebSocket protocols.
  • Fast routing with path parameters.
  • Dependency Injection with Depends.
  • Middleware for request/response manipulation.
  • Automatic schema generation with OpenAPI and JSON Schema.
  • File serving and request parsing support.

Starlette APIs with Examples

Below are some of the most useful APIs that Starlette offers, along with code snippets to help you understand their usage:

Basic Application

  from starlette.applications import Starlette
  from starlette.responses import PlainTextResponse

  app = Starlette(debug=True)

  @app.route("/")
  async def homepage(request):
      return PlainTextResponse("Hello, Starlette!")

This creates a simple application with a single route that returns a plain text response.

Path Parameters

  @app.route("/greet/{name}")
  async def greet(request):
      name = request.path_params["name"]
      return PlainTextResponse(f"Hello, {name}!")

Access dynamic segments of the URL via path_params.

Query Parameters

  @app.route("/search")
  async def search(request):
      query = request.query_params.get("query", "default")
      return PlainTextResponse(f"Search query: {query}")

Extract query parameters using query_params.

Middleware

  from starlette.middleware.base import BaseHTTPMiddleware

  class CustomMiddleware(BaseHTTPMiddleware):
      async def dispatch(self, request, call_next):
          response = await call_next(request)
          response.headers["X-Custom-Header"] = "CustomValue"
          return response

  app.add_middleware(CustomMiddleware)

Use middleware to modify requests or responses during the application lifecycle.

WebSocket Support

  @app.websocket_route("/ws")
  async def websocket_endpoint(websocket):
      await websocket.accept()
      data = await websocket.receive_text()
      await websocket.send_text(f"Message received: {data}")
      await websocket.close()

Handle WebSocket connections for real-time features.

Static File Handling

  from starlette.staticfiles import StaticFiles
  
  app.mount("/static", StaticFiles(directory="static"), name="static")

This serves files from the static/ directory at the /static endpoint.

Dependency Injection

  from starlette.requests import Request
  from starlette.responses import JSONResponse
  from starlette.dependencies import Depends

  async def query_user(request: Request):
      return {"user": "Jane Doe"}

  @app.route("/user")
  async def user_info(info=Depends(query_user)):
      return JSONResponse(info)

Leverage Depends for better modularity and testability.

Using Background Tasks

  from starlette.background import BackgroundTasks

  async def log_message(message: str):
      with open("log.txt", "a") as log_file:
          log_file.write(message + "\n")

  @app.route("/notify")
  async def send_notification(background_tasks: BackgroundTasks):
      background_tasks.add_task(log_message, "New notification triggered!")
      return PlainTextResponse("Notification sent.")

Perform background tasks without delaying the response.

Complete Application Example

Here is a complete example that ties together all the concepts we have discussed above:

  from starlette.applications import Starlette
  from starlette.responses import JSONResponse, PlainTextResponse
  from starlette.routing import Route, WebSocketRoute
  from starlette.staticfiles import StaticFiles
  from starlette.background import BackgroundTasks
  from starlette.middleware.base import BaseHTTPMiddleware

  async def homepage(request):
      return PlainTextResponse("Welcome to Starlette!")

  async def greet(request):
      name = request.path_params.get("name", "User")
      return PlainTextResponse(f"Hello, {name}!")

  async def log_message(message: str):
      with open("log.txt", "a") as log_file:
          log_file.write(message + "\n")

  async def send_notification(background_tasks: BackgroundTasks):
      background_tasks.add_task(log_message, "Notification triggered!")
      return PlainTextResponse("Notification sent and logged.")

  async def websocket_endpoint(websocket):
      await websocket.accept()
      data = await websocket.receive_text()
      await websocket.send_text(f"Received: {data}")
      await websocket.close()

  class CustomMiddleware(BaseHTTPMiddleware):
      async def dispatch(self, request, call_next):
          response = await call_next(request)
          response.headers["X-Custom-Header"] = "Middleware Applied"
          return response

  routes = [
      Route("/", endpoint=homepage),
      Route("/greet/{name}", endpoint=greet),
      Route("/notify", endpoint=send_notification),
      WebSocketRoute("/ws", endpoint=websocket_endpoint),
  ]

  app = Starlette(debug=True, routes=routes)
  app.add_middleware(CustomMiddleware)
  app.mount("/static", StaticFiles(directory="static"), name="static")

This example demonstrates how to use Starlette’s routing, middleware, WebSocket support, background tasks, and static file serving in a cohesive application.

Conclusion

Starlette is a powerful and versatile framework for building modern web applications and APIs. Its lightweight design and extensive feature set make it a great choice for projects of any scale. Whether you’re creating a simple API or a complex service, Starlette has you covered.

Leave a Reply

Your email address will not be published. Required fields are marked *