bhylu.com

Advertisements

Go HTTP Validation

Refuse an oversized or malformed request before accepting its fields.

How it works

Bound the body with http.MaxBytesReader before decoding it. Reject unexpected methods and media types, refuse unknown fields, require a single JSON object and validate its domain values. Parsing is only one boundary: this fixed local demo has no login, persistence, payment or public deployment.

Run this Go example

Install Go separately from the official Go downloads and check go version in a new terminal. The reviewed baseline is Go 1.27.3 on Windows amd64; the authored syntax and standard-library APIs require Go 1.22 or newer. Save the complete source below as http-validation.go in a learning folder, then run go run http-validation.go from that folder. These examples use only the standard library.

Bhylu has no Go browser runner. Apache, MySQL, PHP and the JavaScript or Python playground are not required to run these files. File examples own a temporary directory; HTTP client examples create an ephemeral loopback server and close it. They do not contact an external API.

Download the complete http-validation.go · Download all source files with hash checks

For the optional collection download, save download-examples.mjs in a new learning folder and run node download-examples.mjs. A local preview uses node download-examples.mjs http://127.0.0.1:8000/examples/go/. The downloader refuses an existing bhylu-go-examples folder and installs or executes no Go code.

Example

http-validation.go

package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/http/httptest"
	"strings"
)

func check(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		w.Header().Set("Allow", "POST")
		http.Error(w, "method not allowed", 405)
		return
	}
	if r.Header.Get("Content-Type") != "application/json" {
		http.Error(w, "use application/json", 415)
		return
	}
	r.Body = http.MaxBytesReader(w, r.Body, 256)
	dec := json.NewDecoder(r.Body)
	dec.DisallowUnknownFields()
	var input struct {
		Count int `json:"count"`
	}
	err := dec.Decode(&input)
	if err != nil {
		var large *http.MaxBytesError
		if errors.As(err, &large) {
			http.Error(w, "too large", 413)
		} else {
			http.Error(w, "invalid JSON", 400)
		}
		return
	}
	var extra any
	if err = dec.Decode(&extra); err != io.EOF {
		var large *http.MaxBytesError
		if errors.As(err, &large) {
			http.Error(w, "too large", 413)
		} else {
			http.Error(w, "need one JSON value", 400)
		}
		return
	}
	if input.Count < 1 || input.Count > 20 {
		http.Error(w, "count out of range", 400)
		return
	}
	fmt.Fprintln(w, "accepted for this check only")
}

func main() {
	for _, body := range []string{`{"count":2}`, `{"count":0}`, `{"count":2,"x":1}`, `{"count":2} {}`, strings.Repeat(" ", 300)} {
		req := httptest.NewRequest("POST", "/check", strings.NewReader(body))
		req.Header.Set("Content-Type", "application/json")
		out := httptest.NewRecorder()
		check(out, req)
		fmt.Println(out.Code)
	}
}

Expected result

200
400
400
400
413

MaxBytesReader gives a typed error when the body exceeds the limit. The handler classifies that separately from malformed input and writes success only after all checks. JSON duplicate keys remain accepted by this decoder and are not suitable for ambiguous security-sensitive fields.

For language rules and APIs, use the Go language specification and standard-library documentation. The fictional examples are learning fixtures, not a deployed parcel service.

Advertisements