CodeBlanks Logo Icon CodeBlanks

JSON API

Learn to write an HTTP endpoint returning JSON.

A JSON API

A JSON endpoint follows these steps: validate the request → decode the body → do the work → write a JSON response with a suitable status code. A small helper reduces repetition:

func jsonYaz(w http.ResponseWriter, kod int, v any) {
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(kod)
    json.NewEncoder(w).Encode(v)
}

If errors are returned as JSON too, the client deals with a single format: {"hata":"ad boş olamaz"}.

Validation and 201

An example create endpoint:

func ekle(w http.ResponseWriter, r *http.Request) {
    var u Urun
    r.Body = http.MaxBytesReader(w, r.Body, 1<<20)
    if err := json.NewDecoder(r.Body).Decode(&u); err != nil {
        jsonYaz(w, 400, map[string]string{"hata": "geçersiz JSON"})
        return
    }
    if u.Ad == "" {
        jsonYaz(w, 422, map[string]string{"hata": "ad boş olamaz"})
        return
    }
    jsonYaz(w, 201, u)
}

Practice Create endpoint

Write the jsonYaz and ekle functions above (Urun contains only Ad string `json:"ad"`). Send two POST requests with the bodies {"ad":"Kalem"} and {"ad":""} and print both status codes on one line.

Starter code

main.go
package main

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

func main() {
    // buraya yaz
}

Sample solution

main.go
package main

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

type Urun struct {
    Ad string `json:"ad"`
}

func jsonYaz(w http.ResponseWriter, kod int, v any) {
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(kod)
    json.NewEncoder(w).Encode(v)
}

func ekle(w http.ResponseWriter, r *http.Request) {
    var u Urun
    r.Body = http.MaxBytesReader(w, r.Body, 1<<20)
    if err := json.NewDecoder(r.Body).Decode(&u); err != nil {
        jsonYaz(w, 400, map[string]string{"hata": "geçersiz JSON"})
        return
    }
    if u.Ad == "" {
        jsonYaz(w, 422, map[string]string{"hata": "ad boş olamaz"})
        return
    }
    jsonYaz(w, 201, u)
}

func main() {
    kod := func(govde string) int {
        rec := httptest.NewRecorder()
        ekle(rec, httptest.NewRequest("POST", "/urunler", strings.NewReader(govde)))
        return rec.Code
    }
    fmt.Println(kod(`{"ad":"Kalem"}`), kod(`{"ad":""}`))
}

Expected output

201 422

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 Which limits the size of a request body?

  • w.WriteHeader(413)
  • json.Decoder.Limit
  • http.MaxBytesReader(w, r.Body, n) Correct answer
  • r.ContentLength = n

Explanation: MaxBytesReader cuts reading with an error after n bytes, preventing memory exhaustion with oversized bodies.

2 Content type

Question
w.Header().Set("Content-Type", "____")
json.NewEncoder(w).Encode(v)
Answer
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(v)

Explanation: application/json is the standard MIME type for a JSON body.

3 Situation and code

Term Meaning
Created 201
Bozuk JSON 400
Invalid field 422
Body too large 413

All lessons in Intermediate