Newsletter
TechAnV Blog
Get updates on security engineering, Rust, eBPF, and DevSecOps. No spam, unsubscribe anytime.
Check your inbox and click the confirmation link to complete your subscription.
GPT-4 for API design research#
I came up with a really useful prompt for GPT-4 today. I was considering options for refactoring how Datasette’s core view functions work, and was contemplating alternative ways to dispatch to different functions based on a combination of the URL path and the HTTP verb.
I decided it would be useful to see how other frameworks solved that, and came up with the following prompt:
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
(I added that second line after it first started spitting out installation instructions for each framework, when I just wanted to see some illustrative code examples.)
I got really great results!
It started by kicking out code examples for Flask (Python), Express (JavaScript/Node.js) and Gin (Go).
Then I prompted:
Three more examples for the same languages but showing different frameworks
It gave me Django (Python), Koa (JavaScript/Node.js) and Echo (Go).
Finally, I added:
Some Rust examples too
And it gave me examples for Actix-web and Rocket, both in Rust.
I’ve shared the full transcript here: https://gist.github.com/simonw/fa2379b97420404a81b0fcdb4db79657
As someone who spends a whole lot of time on API design, this feels like a really useful trick - researching how multiple frameworks across multiple other languages solve a problem is incredibly useful for coming up with a coherent new API design.
The examples it gave me#
Here’s just the code from the examples I found most useful:
Flask:
1from flask import Flask2
3app = Flask(__name__)4
5@app.route('/example', methods=['GET'])6def get_example():7 return "This is a GET request."8
9@app.route('/example', methods=['POST'])10def post_example():11 return "This is a POST request."12
13if __name__ == '__main__':14 app.run()Express:
1const express = require('express');2const app = express();3
4app.get('/example', (req, res) => {5 res.send('This is a GET request.');6});7
8app.post('/example', (req, res) => {9 res.send('This is a POST request.');10});11
12app.listen(3000, () => {13 console.log('Server is running on port 3000');14});Gin:
1package main2
3import (4 "github.com/gin-gonic/gin"5)6
7func main() {8 r := gin.Default()9
10 r.GET("/example", func(c *gin.Context) {11 c.String(200, "This is a GET request.")12 })13
14 r.POST("/example", func(c *gin.Context) {15 c.String(200, "This is a POST request.")16 })17
18 r.Run()19}Actix-web:
1use actix_web::{web, App, HttpResponse, HttpServer, Responder};2
3async fn get_example() -> impl Responder {4 HttpResponse::Ok().body("This is a GET request.")5}6
7async fn post_example() -> impl Responder {8 HttpResponse::Ok().body("This is a POST request.")9}10
11#[actix_web::main]12async fn main() -> std::io::Result<()> {13 HttpServer::new(|| {14 App::new()15 .route("/example", web::get().to(get_example))16 .route("/example", web::post().to(post_example))17 })18 .bind("127.0.0.1:8080")?19 .run()20 .await21}Koa:
1const Koa = require('koa');2const Router = require('koa-router');3
4const app = new Koa();5const router = new Router();6
7router.get('/example', (ctx) => {8 ctx.body = 'This is a GET request.';9});10
11router.post('/example', (ctx) => {12 ctx.body = 'This is a POST request.';13});14
15app.use(router.routes());16app.use(router.allowedMethods());17
18app.listen(3000, () => {19 console.log('Server is running on port 3000');20});Django:
1from django.http import HttpResponse2from django.views import View3
4class ExampleView(View):5 def get(self, request):6 return HttpResponse("This is a GET request.")7
8 def post(self, request):9 return HttpResponse("This is a POST request.")1from django.urls import path2from .views import ExampleView3
4urlpatterns = [5 path('example/', ExampleView.as_view(), name='example'),6]Rocket:
1#![feature(proc_macro_hygiene, decl_macro)]2
3#[macro_use] extern crate rocket;4
5use rocket::response::content;6
7#[get("/example")]8fn get_example() -> content::Plain<&'static str> {9 content::Plain("This is a GET request.")10}11
12#[post("/example")]13fn post_example() -> content::Plain<&'static str> {14 content::Plain("This is a POST request.")15}16
17#[launch]18fn rocket() -> _ {19 rocket::build().mount("/", routes![get_example, post_example])20}And from a tip from Jim Flanagan, here’s what it gave me for Elixir/Phoenix:
1defmodule ExampleAppWeb.Router do2 use ExampleAppWeb, :router3
4 pipeline :api do5 plug :accepts, ["json"]6 end7
8 scope "/api", ExampleAppWeb do9 pipe_through :api10
11 get "/example", ExampleController, :get_example12 post "/example", ExampleController, :post_example13 end14end