Skip to content

Instantly share code, notes, and snippets.

@simonw
Last active April 11, 2023 14:49
Show Gist options
  • Save simonw/fa2379b97420404a81b0fcdb4db79657 to your computer and use it in GitHub Desktop.
Save simonw/fa2379b97420404a81b0fcdb4db79657 to your computer and use it in GitHub Desktop.

HTTP Routing Code Examples

2023-04-06 18:58:06

user: Show me code examples of different web frameworks in Python and JavaScript and Go illustrating how HTTP routing works - in particular the problem of mapping an incoming HTTP request to some code based on both the URL path and the HTTP verb

Don't show installation instructions, just get straight to the code snippets


assistant: Sure, I'll provide examples for three popular web frameworks: Flask for Python, Express for JavaScript (Node.js), and Gin for Go. These examples will demonstrate handling an incoming HTTP request based on the URL path and the HTTP verb.

Flask (Python):

from flask import Flask

app = Flask(__name__)

@app.route('/example', methods=['GET'])
def get_example():
    return "This is a GET request."

@app.route('/example', methods=['POST'])
def post_example():
    return "This is a POST request."

if __name__ == '__main__':
    app.run()

Express (JavaScript/Node.js):

const express = require('express');
const app = express();

app.get('/example', (req, res) => {
  res.send('This is a GET request.');
});

app.post('/example', (req, res) => {
  res.send('This is a POST request.');
});

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

Gin (Go):

package main

import (
	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()

	r.GET("/example", func(c *gin.Context) {
		c.String(200, "This is a GET request.")
	})

	r.POST("/example", func(c *gin.Context) {
		c.String(200, "This is a POST request.")
	})

	r.Run()
}

In each of these examples, an HTTP server is created to handle incoming requests. The server listens for GET and POST requests at the /example path, and it will call the appropriate function depending on the request's HTTP verb.


user: Three more examples for the same languages but showing different frameworks


assistant: Sure, here are three more examples using different web frameworks for Python, JavaScript (Node.js), and Go:

Django (Python):

In views.py:

from django.http import HttpResponse
from django.views import View

class ExampleView(View):
    def get(self, request):
        return HttpResponse("This is a GET request.")

    def post(self, request):
        return HttpResponse("This is a POST request.")

In urls.py:

from django.urls import path
from .views import ExampleView

urlpatterns = [
    path('example/', ExampleView.as_view(), name='example'),
]

Koa (JavaScript/Node.js):

const Koa = require('koa');
const Router = require('koa-router');

const app = new Koa();
const router = new Router();

router.get('/example', (ctx) => {
  ctx.body = 'This is a GET request.';
});

router.post('/example', (ctx) => {
  ctx.body = 'This is a POST request.';
});

app.use(router.routes());
app.use(router.allowedMethods());

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

Echo (Go):

package main

import (
	"github.com/labstack/echo/v4"
	"net/http"
)

func getExample(c echo.Context) error {
	return c.String(http.StatusOK, "This is a GET request.")
}

func postExample(c echo.Context) error {
	return c.String(http.StatusOK, "This is a POST request.")
}

func main() {
	e := echo.New()

	e.GET("/example", getExample)
	e.POST("/example", postExample)

	e.Start(":8080")
}

These examples demonstrate the same functionality as the previous ones: listening for GET and POST requests at the /example path and executing the appropriate function depending on the request's HTTP verb. Each example utilizes a different web framework for the given language.


user: Some Rust examples too


assistant: Sure, here are two examples of Rust web frameworks illustrating HTTP routing based on URL paths and HTTP verbs:

Actix-web (Rust):

use actix_web::{web, App, HttpResponse, HttpServer, Responder};

async fn get_example() -> impl Responder {
    HttpResponse::Ok().body("This is a GET request.")
}

async fn post_example() -> impl Responder {
    HttpResponse::Ok().body("This is a POST request.")
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new()
            .route("/example", web::get().to(get_example))
            .route("/example", web::post().to(post_example))
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}

Rocket (Rust):

Note: Rocket requires nightly Rust.

In Cargo.toml:

[dependencies]
rocket = "0.5.0-rc.1"

In main.rs:

#![feature(proc_macro_hygiene, decl_macro)]

#[macro_use] extern crate rocket;

use rocket::response::content;

#[get("/example")]
fn get_example() -> content::Plain<&'static str> {
    content::Plain("This is a GET request.")
}

#[post("/example")]
fn post_example() -> content::Plain<&'static str> {
    content::Plain("This is a POST request.")
}

#[launch]
fn rocket() -> _ {
    rocket::build().mount("/", routes![get_example, post_example])
}

Both examples create an HTTP server that listens for GET and POST requests at the /example path. The server will call the appropriate function depending on the request's HTTP verb. The Actix-web example uses the actix_web crate, while the Rocket example uses the rocket crate.


user: Any more Python frameworks that use decorators like Flask does?


assistant: Yes, there are other Python web frameworks that use decorators similar to Flask. One such example is FastAPI, which is an asynchronous web framework built on top of Starlette and Pydantic for building APIs with Python 3.7+ based on standard Python type hints.

Here's an example of how FastAPI uses decorators for HTTP routing:

FastAPI (Python):

from fastapi import FastAPI

app = FastAPI()

@app.get("/example")
async def get_example():
    return {"message": "This is a GET request."}

@app.post("/example")
async def post_example():
    return {"message": "This is a POST request."}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="127.0.0.1", port=8000)

In this example, FastAPI is used to create an HTTP server that listens for GET and POST requests at the /example path. The server will call the appropriate function depending on the request's HTTP verb, using decorators similar to Flask.


user: Any others? Just show example code


assistant: Sure, here's another example of a Python web framework that uses decorators for HTTP routing. This example uses the Bottle web framework.

Bottle (Python):

from bottle import Bottle, run

app = Bottle()

@app.route('/example', method='GET')
def get_example():
    return "This is a GET request."

@app.route('/example', method='POST')
def post_example():
    return "This is a POST request."

if __name__ == '__main__':
    run(app, host='localhost', port=8080)

In this example, the Bottle web framework is used to create an HTTP server that listens for GET and POST requests at the /example path. The server will call the appropriate function depending on the request's HTTP verb, using decorators similar to Flask.


user: What do those frameworks do with an HTTP request using a verb like HEAD or OPTIONS ?


assistant: Each web framework handles HTTP requests with verbs like HEAD or OPTIONS differently. Generally, if you don't define specific routes to handle these verbs, the web framework will either return a default response or a 405 Method Not Allowed error, depending on the framework's behavior.

Here's a brief overview of how the mentioned web frameworks handle HEAD and OPTIONS requests:

  1. Flask (Python):

    • HEAD: If you don't define a route for the HEAD method, Flask will automatically handle it by invoking the GET route handler for the same URL and discarding the response body, if a GET route exists.
    • OPTIONS: Flask will automatically generate an OPTIONS response based on the available methods for the URL, unless you explicitly define a route handler for the OPTIONS method.
  2. Django (Python):

    • HEAD: Django will automatically handle HEAD requests in a similar way to Flask. It invokes the GET route handler and discards the response body.
    • OPTIONS: Django provides a default implementation of the OPTIONS method in its base view class, which returns information about the allowed methods for the requested resource.
  3. FastAPI (Python):

    • HEAD: FastAPI does not automatically handle HEAD requests. You need to define a route handler for the HEAD method.
    • OPTIONS: FastAPI does not automatically handle OPTIONS requests. You need to define a route handler for the OPTIONS method.
  4. Bottle (Python):

    • HEAD: Bottle will automatically handle HEAD requests by invoking the GET route handler and discarding the response body, if a GET route exists.
    • OPTIONS: Bottle does not automatically handle OPTIONS requests. You need to define a route handler for the OPTIONS method.
  5. Express (JavaScript/Node.js):

    • HEAD: Express does not automatically handle HEAD requests. You need to define a route handler for the HEAD method.
    • OPTIONS: Express does not automatically handle OPTIONS requests. You need to define a route handler for the OPTIONS method.
  6. Koa (JavaScript/Node.js):

    • HEAD: Koa does not automatically handle HEAD requests. You need to define a route handler for the HEAD method.
    • OPTIONS: Koa does not automatically handle OPTIONS requests. You need to define a route handler for the OPTIONS method.
  7. Gin (Go):

    • HEAD: Gin does not automatically handle HEAD requests. You need to define a route handler for the HEAD method.
    • OPTIONS: Gin does not automatically handle OPTIONS requests. You need to define a route handler for the OPTIONS method.
  8. Echo (Go):

    • HEAD: Echo does not automatically handle HEAD requests. You need to define a route handler for the HEAD method.
    • OPTIONS: Echo does not automatically handle OPTIONS requests. You need to define a route handler for the OPTIONS method.
  9. Actix-web (Rust):

    • HEAD: Actix-web does not automatically handle HEAD requests. You need to define a route handler for the HEAD method.
    • OPTIONS: Actix-web does not automatically handle OPTIONS requests. You need to define a route handler for the OPTIONS method.
  10. Rocket (Rust):

    • HEAD: Rocket does not automatically handle HEAD requests. You need to define a route handler for the HEAD method.
    • OPTIONS: Rocket does not automatically handle OPTIONS requests. You need to define a route handler for the OPTIONS method.

In general, it's a good practice to define route handlers for the HEAD and OPTIONS methods if your API should support them, as this gives you more control over the responses and allows you to implement custom behavior as needed.


user: Show me an example for Elixir/Phoenix


assistant: Here's an example of handling HTTP routing in Elixir using the Phoenix web framework:

  1. First, install the Phoenix project generator if you haven't already:
mix archive.install hex phx_new 1.6.0
  1. Create a new Phoenix application:
mix phx.new example_app
cd example_app
  1. Modify the lib/example_app_web/router.ex file to define the routes for GET and POST requests:
defmodule ExampleAppWeb.Router do
  use ExampleAppWeb, :router

  pipeline :api do
    plug :accepts, ["json"]
  end

  scope "/api", ExampleAppWeb do
    pipe_through :api

    get "/example", ExampleController, :get_example
    post "/example", ExampleController, :post_example
  end
end
  1. Create a new file lib/example_app_web/controllers/example_controller.ex to define the controller with the corresponding functions for the GET and POST requests:
defmodule ExampleAppWeb.ExampleController do
  use ExampleAppWeb, :controller

  def get_example(conn, _params) do
    json(conn, %{message: "This is a GET request."})
  end

  def post_example(conn, _params) do
    json(conn, %{message: "This is a POST request."})
  end
end
  1. Start the Phoenix server:
mix phx.server

In this example, the Phoenix web framework is used to create an HTTP server that listens for GET and POST requests at the /api/example path. The server will call the appropriate function in the ExampleController depending on the request's HTTP verb.


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment