From 8868dac428d9d5611a458818a20ae369b7c42c0b Mon Sep 17 00:00:00 2001 From: Arseny Balobanov Date: Thu, 24 Mar 2022 18:48:48 +0300 Subject: [PATCH] [coverme] Add finish todo handler. --- coverme/README.md | 22 +++++++++++++++++++--- coverme/app/app.go | 27 +++++++++++++++++++++------ coverme/client/client.go | 16 ++++++++++++++++ coverme/models/storage.go | 14 ++++++++++++++ 4 files changed, 70 insertions(+), 9 deletions(-) diff --git a/coverme/README.md b/coverme/README.md index 0efcaa2..042c2f5 100644 --- a/coverme/README.md +++ b/coverme/README.md @@ -44,7 +44,7 @@ Todo-app с минимальной функциональностью + client. Health check: ``` -✗ curl -i -X GET localhost:6029/ +✗ curl -i -X GET localhost:6029/ HTTP/1.1 200 OK Content-Type: application/json Date: Thu, 19 Mar 2020 21:46:02 GMT @@ -66,7 +66,7 @@ Content-Length: 51 Получить todo по id: ``` -✗ curl -i localhost:6029/todo/0 +✗ curl -i localhost:6029/todo/0 HTTP/1.1 200 OK Content-Type: application/json Date: Thu, 19 Mar 2020 21:44:17 GMT @@ -77,7 +77,7 @@ Content-Length: 51 Получить все todo: ``` -✗ curl -i -X GET localhost:6029/todo +✗ curl -i -X GET localhost:6029/todo HTTP/1.1 200 OK Content-Type: application/json Date: Thu, 19 Mar 2020 21:44:37 GMT @@ -85,3 +85,19 @@ Content-Length: 53 [{"id":0,"title":"A","content":"a","finished":false}] ``` + +Завершить todo: +``` +✗ curl -i -X POST localhost:6029/todo/0/finish +HTTP/1.1 200 OK +Date: Thu, 24 Mar 2022 15:40:49 GMT +Content-Length: 0 + +✗ curl -i -X GET localhost:6029/todo +HTTP/1.1 200 OK +Content-Type: application/json +Date: Thu, 24 Mar 2022 15:41:04 GMT +Content-Length: 52 + +[{"id":0,"title":"A","content":"a","finished":true}]% +``` diff --git a/coverme/app/app.go b/coverme/app/app.go index c9387cd..22d39b6 100644 --- a/coverme/app/app.go +++ b/coverme/app/app.go @@ -9,7 +9,6 @@ import ( "net/http" "os" "strconv" - "strings" "github.com/gorilla/handlers" "github.com/gorilla/mux" @@ -34,10 +33,11 @@ func (app *App) Start(port int) { func (app *App) initRoutes() { app.router = mux.NewRouter() - app.router.HandleFunc("/", app.status).Methods("Get") - app.router.HandleFunc("/todo", app.list).Methods("Get") - app.router.HandleFunc("/todo/{id:[0-9]+}", app.getTodo).Methods("Get") - app.router.HandleFunc("/todo/create", app.addTodo).Methods("Post") + app.router.HandleFunc("/", app.status).Methods("GET") + app.router.HandleFunc("/todo", app.list).Methods("GET") + app.router.HandleFunc("/todo/{id:[0-9]+}", app.getTodo).Methods("GET") + app.router.HandleFunc("/todo/{id:[0-9]+}/finish", app.finishTodo).Methods("POST") + app.router.HandleFunc("/todo/create", app.addTodo).Methods("POST") } func (app *App) run(addr string) { @@ -80,7 +80,7 @@ func (app *App) addTodo(w http.ResponseWriter, r *http.Request) { } func (app *App) getTodo(w http.ResponseWriter, r *http.Request) { - id, err := strconv.Atoi(strings.TrimPrefix(r.URL.Path, "/todo/")) + id, err := strconv.Atoi(mux.Vars(r)["id"]) if err != nil { utils.BadRequest(w, "ID must be an int") return @@ -95,6 +95,21 @@ func (app *App) getTodo(w http.ResponseWriter, r *http.Request) { _ = utils.RespondJSON(w, http.StatusOK, todo) } +func (app *App) finishTodo(w http.ResponseWriter, r *http.Request) { + id, err := strconv.Atoi(mux.Vars(r)["id"]) + if err != nil { + utils.BadRequest(w, "ID must be an int") + return + } + + if err := app.db.FinishTodo(models.ID(id)); err != nil { + utils.ServerError(w) + return + } + + w.WriteHeader(http.StatusOK) +} + func (app *App) status(w http.ResponseWriter, r *http.Request) { _ = utils.RespondJSON(w, http.StatusOK, "API is up and working!") } diff --git a/coverme/client/client.go b/coverme/client/client.go index cac5a08..b3bbe22 100644 --- a/coverme/client/client.go +++ b/coverme/client/client.go @@ -69,3 +69,19 @@ func (c *Client) List() ([]*models.Todo, error) { err = json.NewDecoder(resp.Body).Decode(&todos) return todos, err } + +func (c *Client) Finish(id models.ID) error { + u := fmt.Sprintf("%s/todo/%d/finish", c.addr, id) + + resp, err := http.Post(u, "application/json", nil) + if err != nil { + return err + } + defer func() { _ = resp.Body.Close() }() + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("unexpected status code %d", resp.StatusCode) + } + + return err +} diff --git a/coverme/models/storage.go b/coverme/models/storage.go index 07185ee..c4fc981 100644 --- a/coverme/models/storage.go +++ b/coverme/models/storage.go @@ -12,6 +12,7 @@ type Storage interface { AddTodo(string, string) (*Todo, error) GetTodo(ID) (*Todo, error) GetAll() ([]*Todo, error) + FinishTodo(ID) error } type InMemoryStorage struct { @@ -69,3 +70,16 @@ func (s *InMemoryStorage) GetAll() ([]*Todo, error) { return out, nil } + +func (s *InMemoryStorage) FinishTodo(id ID) error { + s.mu.Lock() + defer s.mu.Unlock() + + todo, ok := s.todos[id] + if !ok { + return fmt.Errorf("todo %d not found", id) + } + + todo.MarkFinished() + return nil +}