Do each one yourself, then tap it to tick it off. The ticks are only a checklist for you: they are not marked or scored.
0 of 5 done
Example
Minimal API
This example stores tasks in memory. It shows typed handlers, maps, JSON, and method checks. Use this pattern with the types you created earlier in the track.
For Go 1.27, encoding/json keeps the familiar API while using the newer implementation behind it, so this code stays simple.
package main
import (
"encoding/json"
"log"
"net/http"
"strconv"
"strings"
)
type Task struct {
ID int `json:"id"`
Text string `json:"text"`
Done bool `json:"done"`
}
type CreateTaskRequest struct {
Text string `json:"text"`
}
type ErrorResponse struct {
Error string `json:"error"`
}
var tasks = map[int]Task{}
var nextID = 1
func writeJSON(w http.ResponseWriter, status int, v any) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
json.NewEncoder(w).Encode(v)
}
func writeError(w http.ResponseWriter, status int, msg string) {
writeJSON(w, status, ErrorResponse{Error: msg})
}
func tasksHandler(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
list := make([]Task, 0, len(tasks))
for _, task := range tasks {
list = append(list, task)
}
writeJSON(w, http.StatusOK, list)
case http.MethodPost:
var req CreateTaskRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
writeError(w, http.StatusBadRequest, "invalid JSON body")
return
}
req.Text = strings.TrimSpace(req.Text)
if req.Text == "" {
writeError(w, http.StatusBadRequest, "text is required")
return
}
task := Task{ID: nextID, Text: req.Text}
tasks[nextID] = task
nextID++
writeJSON(w, http.StatusCreated, task)
default:
writeError(w, http.StatusMethodNotAllowed, "method not allowed")
}
}
func taskByIDHandler(w http.ResponseWriter, r *http.Request) {
idText := strings.TrimPrefix(r.URL.Path, "/tasks/")
id, err := strconv.Atoi(idText)
if err != nil {
writeError(w, http.StatusBadRequest, "invalid task id")
return
}
task, ok := tasks[id]
if !ok {
writeError(w, http.StatusNotFound, "task not found")
return
}
writeJSON(w, http.StatusOK, task)
}
func main() {
http.HandleFunc("/tasks", tasksHandler)
http.HandleFunc("/tasks/", taskByIDHandler)
log.Println("listening on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
Tip
Test with curl
Keep sample curl commands in your README. They prove your service runs without needing Postman or a frontend.
Run the server in one terminal. Use curl from another terminal.
go run .
curl http://localhost:8080/tasks
curl -X POST http://localhost:8080/tasks \
-H "Content-Type: application/json" \
-d '{"text":"pay mess bill by UPI"}'
curl http://localhost:8080/tasks/1
Common mistake
Do not hide errors
A common beginner mistake is returning plain text errors sometimes and JSON errors other times. Pick one style for your API.
Also, do not ignore json.NewDecoder errors. Bad input should get a 400 response, not a fake empty task.
Your to-do
Do this now
Do each one yourself, then tap it to tick it off. The ticks are only a checklist for you: they are not marked or scored.