Challenge 2 - HTTP service
- Go course
- Intermediate
- Lesson 78/80
- 8 min
Write a JSON-returning service with net/http.
Challenge: a notes API
You will write a small HTTP service that keeps notes in memory:
POST /notlar: adds a note with a{"metin":"..."}body and returns201with the added note (including its id). An empty text gives400.GET /notlar: returns all notes as a JSON array.
type Not struct {
ID int `json:"id"`
Metin string `json:"metin"`
}The notes are kept in a slice protected by a sync.Mutex.
Plan
1) type Depo struct { mu sync.Mutex; notlar []Not; sonID int }. 2) mux.HandleFunc("POST /notlar", ...): decode the body, 400 if empty, otherwise lock, sonID++, append, 201 + JSON. 3) mux.HandleFunc("GET /notlar", ...): lock and write the list as JSON. 4) Send a POST and a GET with httptest and check the result.
Practice Build the service
Implement the plan. Send a POST with the body {"metin":"süt al"}, then print the body of the GET response.
Starter code
package main
import (
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"strings"
"sync"
)
func main() {
// buraya yaz
}Sample solution
package main
import (
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"strings"
"sync"
)
type Not struct {
ID int `json:"id"`
Metin string `json:"metin"`
}
type Depo struct {
mu sync.Mutex
notlar []Not
sonID int
}
func main() {
d := &Depo{notlar: []Not{}}
mux := http.NewServeMux()
mux.HandleFunc("POST /notlar", func(w http.ResponseWriter, r *http.Request) {
var n Not
if err := json.NewDecoder(r.Body).Decode(&n); err != nil || n.Metin == "" {
http.Error(w, "geçersiz not", http.StatusBadRequest)
return
}
d.mu.Lock()
d.sonID++
n.ID = d.sonID
d.notlar = append(d.notlar, n)
d.mu.Unlock()
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(n)
})
mux.HandleFunc("GET /notlar", func(w http.ResponseWriter, r *http.Request) {
d.mu.Lock()
defer d.mu.Unlock()
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(d.notlar)
})
mux.ServeHTTP(httptest.NewRecorder(), httptest.NewRequest("POST", "/notlar", strings.NewReader(`{"metin":"süt al"}`)))
rec := httptest.NewRecorder()
mux.ServeHTTP(rec, httptest.NewRequest("GET", "/notlar", nil))
fmt.Print(rec.Body.String())
}Expected output
[{"id":1,"metin":"süt al"}]
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 If you want the GET response to be <code>[]</code> instead of <code>null</code> when the list is empty, what do you do?
- Add omitempty
- Write the response as a string
- It isn't possible
- Initialize the slice with []Not{} Correct answer
Explanation: A nil slice encodes as null in JSON; an empty non-nil slice encodes as [].
2 Created code
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.____)
json.NewEncoder(w).Encode(n)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(n)
Explanation: 201 Created is returned when a new resource is added.
3 Request and response
| Term | Meaning |
|---|---|
POST with valid text |
201 + note |
POST with empty text |
400 |
GET |
200 + array |
PUT /notlar |
405 |