Skip to content

Latest commit

 

History

History
147 lines (113 loc) · 3.42 KB

File metadata and controls

147 lines (113 loc) · 3.42 KB

Go 1.22+ net/http Server

To use purely net/http (for Go 1.22+), you will want a configuration file such as:

# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/v2.8.0/configuration-schema.json
package: api
generate:
  std-http-server: true
  models: true
output: gen.go

Generated code

As of Go 1.22, enhancements have been made to the routing of the net/http package in the standard library, which makes it a great starting point for implementing a server with, before needing to reach for another router or a full framework.

For instance, let's take this straightforward specification:

openapi: "3.0.0"
info:
  version: 1.0.0
  title: Minimal ping API server
paths:
  /ping:
    get:
      responses:
        '200':
          description: pet response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pong'
components:
  schemas:
    # base types
    Pong:
      type: object
      required:
        - ping
      properties:
        ping:
          type: string
          example: pong

This then generates code such as:

// Pong defines model for Pong.
type Pong struct {
	Ping string `json:"ping"`
}

// ServerInterface represents all server handlers.
type ServerInterface interface {

	// (GET /ping)
	GetPing(w http.ResponseWriter, r *http.Request)
}

func HandlerFromMux(si ServerInterface, m ServeMux) http.Handler {
	return HandlerWithOptions(si, StdHTTPServerOptions{
		BaseRouter: m,
	})
}

// HandlerWithOptions creates http.Handler with additional options
func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.Handler {
	m := options.BaseRouter

	// ... omitted for brevity

	m.HandleFunc("GET "+options.BaseURL+"/ping", wrapper.GetPing)

	return m
}

To implement this HTTP server, we need to write the following code in our api/impl.go:

import (
	"encoding/json"
	"net/http"
)

// optional code omitted

type Server struct{}

func NewServer() Server {
	return Server{}
}

// (GET /ping)
func (Server) GetPing(w http.ResponseWriter, r *http.Request) {
	resp := Pong{
		Ping: "pong",
	}

	w.WriteHeader(http.StatusOK)
	_ = json.NewEncoder(w).Encode(resp)
}

Now we've got our implementation, we can then write the following code to wire it up and get a running server:

import (
	"log"
	"net/http"

	"github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/stdhttp/api"
)

func main() {
	// create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
	server := api.NewServer()

	r := http.NewServeMux()

	// get an `http.Handler` that we can use
	h := api.HandlerFromMux(server, r)

	s := &http.Server{
		Handler: h,
		Addr:    "0.0.0.0:8080",
	}

	// And we serve HTTP until the world ends.
	log.Fatal(s.ListenAndServe())
}

Note

This doesn't include validation of incoming requests.

Note

If you feel like you've done everything right, but are still receiving 404 page not found errors, make sure that you've got the go directive in your go.mod set to at least 1.22, which enables the enhanced net/http routing. In practice it should be at least:

go 1.24

(the github.com/oapi-codegen/runtime module imported by the generated code requires Go 1.24+.)