Tutorial: a tiny JSON HTTP service in Go 1.26 using new(expression)
Step by step: install Go 1.26, write a 35-line HTTP service that returns JSON with an optional field set via new(21.5), run it, verify the output, and fix common errors.
Updated Reviewed
On this page
By Ada Brackett — Solnyxus editorial voice. Drafted with AI assistance; reviewed by the team.
This is the durable, step-by-step companion to the blog post on Go 1.26's new(expression). Written for Go 1.26.0; tested on Linux (amd64) on 14 October 2026.
What you will build
A single-file web service listening on 127.0.0.1:8080 with one route, GET /reading, that returns JSON. The temp_c field is a *float64 set with new(21.5), a form that is valid from Go 1.26.
Prerequisites
- A terminal and a text editor.
curlfor testing.- Go 1.26 or newer, or Go 1.21+ able to download toolchains automatically (see below).
- Port 8080 free on your machine.
1. Install or select Go 1.26
Check what you have:
go version
If it prints go1.26 or higher, continue. If you have Go 1.21 or newer but older than 1.26, you can let Go fetch the right toolchain by prefixing commands with an environment variable:
export GOTOOLCHAIN=go1.26.0
go version
The first run downloads the toolchain; later runs reuse it. Otherwise install Go from the official download page at go.dev/dl.
2. Create the module
mkdir tiny && cd tiny
go mod init tiny
Open go.mod and ensure the version line reads go 1.26 (adjust it if go mod init wrote an older value):
module tiny
go 1.26
3. Write the code
Save as main.go:
package main
import (
"encoding/json"
"errors"
"log"
"net/http"
"time"
)
type Reading struct {
Sensor string `json:"sensor"`
Temp *float64 `json:"temp_c"`
At string `json:"at"`
}
func readingHandler(w http.ResponseWriter, r *http.Request) {
rd := Reading{
Sensor: "kitchen",
Temp: new(21.5),
At: time.Now().UTC().Format(time.RFC3339),
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(rd); err != nil {
log.Println("encode:", err)
}
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("GET /reading", readingHandler)
srv := &http.Server{Addr: "127.0.0.1:8080", Handler: mux, ReadHeaderTimeout: 5 * time.Second}
log.Println("listening on", srv.Addr)
if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
log.Fatal(err)
}
}
Notes: new(21.5) allocates a float64 initialised to 21.5 and returns *float64. The "GET /reading" pattern restricts the route to GET (method patterns exist since Go 1.22).
4. Check it compiles
gofmt -l .
go vet ./...
go build -o tiny .
gofmt -l prints nothing when formatting is right; go vet and go build print nothing on success.
5. Run it
./tiny
You should see a log line listening on 127.0.0.1:8080. (Or use go run ..)
6. How to know it worked
In a second terminal:
curl -i localhost:8080/reading
Expect HTTP/1.1 200 OK, Content-Type: application/json, and a body like:
{"sensor":"kitchen","temp_c":21.5,"at":"2026-10-14T16:06:23Z"}
The timestamp will differ. Then confirm the method restriction:
curl -i -X POST localhost:8080/reading
Expect 405 Method Not Allowed. Stop the server with Ctrl+C.
Common errors
| Symptom | Likely cause | Fix |
|---|---|---|
new(21.5) (untyped float constant) is not a type or similar | Toolchain or go line in go.mod older than 1.26 | Run go version; set GOTOOLCHAIN=go1.26.0; set go 1.26 in go.mod |
listen tcp 127.0.0.1:8080: bind: address already in use | Another process uses the port | Stop it, or change Addr to another port |
go: toolchain not available or download fails | No network, or proxy blocks downloads | Install Go 1.26 manually from go.dev/dl |
curl: (7) Failed to connect | Server not running, or wrong port | Start it and check the log line |
imported and not used | A pasted import has no use | Remove the unused import |
Variations
- Return
nilforTempto see"temp_c":null. - Replace
new(21.5)with a function call, e.g.new(readSensor()), since any expression is allowed.
Reference
Go 1.26 Release Notes, section "Language": go.dev/doc/go1.26 (checked 14 October 2026).