CodeBlanks Logo Icon CodeBlanks

Meydan okuma 2 - HTTP servis

net/http ile JSON döndüren bir servis yazarsın.

Meydan okuma: not defteri API'si

Bellekte notları tutan küçük bir HTTP servisi yazacaksın:

  • POST /notlar: {"metin":"..."} gövdesiyle not ekler, 201 ve eklenen notu (id dahil) döndürür. Metin boşsa 400.
  • GET /notlar: tüm notları JSON dizi olarak döndürür.
type Not struct {
    ID    int    `json:"id"`
    Metin string `json:"metin"`
}

Notlar sync.Mutex ile korunan bir dilimde tutulur.

Plan

1) type Depo struct { mu sync.Mutex; notlar []Not; sonID int }. 2) mux.HandleFunc("POST /notlar", ...): gövdeyi çöz, boşsa 400, değilse kilitle, sonID++, ekle, 201 + JSON. 3) mux.HandleFunc("GET /notlar", ...): kilitle, listeyi JSON yaz. 4) httptest ile bir POST ve bir GET gönderip sonucu kontrol et.

Uygulama Servisi kur

Planı uygula. {"metin":"süt al"} gövdesiyle POST gönder, ardından GET yanıtının gövdesini yazdır.

Başlangıç kodu

main.go
package main

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

func main() {
    // buraya yaz
}

Örnek çözüm

main.go
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())
}

Beklenen çıktı

[{"id":1,"metin":"süt al"}]

Soru ve cevaplar

Dersin sorularını cevaplarıyla birlikte inceleyebilirsin. Kendini denemek istersen dersi interaktif olarak çöz.

1 Not listesi boşken GET yanıtı <code>null</code> yerine <code>[]</code> olsun istiyorsan ne yaparsın?

  • omitempty eklersin
  • Yanıtı string olarak yazarsın
  • Mümkün değildir
  • Dilimi []Not{} ile başlatırsın Doğru cevap

Açıklama: nil dilim JSON'da null, boş ama nil olmayan dilim [] olarak kodlanır.

2 Oluşturuldu kodu

Soru
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.____)
json.NewEncoder(w).Encode(n)
Cevap
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(n)

Açıklama: Yeni kaynak eklendiğinde 201 Created döndürülür.

3 İstek ve yanıt

Kavram Anlamı
POST geçerli metin 201 + not
POST boş metin 400
GET 200 + dizi
PUT /notlar 405

Orta seviye bölümündeki tüm dersler