From a0b1ea2d65e4c007909a274612c356d5bc8d0907 Mon Sep 17 00:00:00 2001 From: Evgeny Gavriluk Date: Mon, 16 Oct 2023 18:45:18 +0300 Subject: [PATCH 1/8] iter 1 start server --- cmd/shortener/main.go | 106 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-) diff --git a/cmd/shortener/main.go b/cmd/shortener/main.go index 38dd16d..82df0cd 100644 --- a/cmd/shortener/main.go +++ b/cmd/shortener/main.go @@ -1,3 +1,107 @@ package main -func main() {} +import ( + "encoding/base64" + "errors" + "fmt" + "net/http" + "io" +) + +var urls map[string]string // хранилище ссылок + +func main() { + + urls = make(map[string]string) + + mux := http.NewServeMux() + mux.HandleFunc("/", checkMethod) + + fmt.Println("Server is starter") + err := http.ListenAndServe(":8080", mux) + if err != nil { + panic(err) + } +} + +// Роутер перенаправляет на обработчик запросов POST или GET +func checkMethod(rw http.ResponseWriter, rq *http.Request) { + fmt.Println("Пришел метод", rq.Method) + if rq.Method == http.MethodPost { + handlerPost(rw, rq) + } + if rq.Method == http.MethodGet { + handlerGet(rw, rq) + } +} + +// Обрабатывает POST-запрос. Возвращает заголовок со статусом 201, если результат Ок +func handlerPost(rw http.ResponseWriter, rq *http.Request) { + fmt.Println("Отрабатывает метод", rq.Method) + // Проверяем, есть ли в теле запроса данные (ссылка) + body, _ := io.ReadAll(rq.Body) + + if string(body) != "" { + // Сокращаем принятую ссылку + res, err := encodeURL(string(body)) + + // Если ошибки нет, возвращаем результат сокращения в заголовке + // а также сохраняем короткую ссылку в хранилище + + if err == nil { + urls[res] = string(body) + rw.Header().Set("Content-Type", "text/plain") + rw.WriteHeader(201) + rw.Write([]byte("http://localhost:8080/" + res)) + } else { + panic("Something wrong in encoding") + } + + } else { + rw.WriteHeader(400) + rw.Write([]byte("No URL in request")) + } +} + +func handlerGet(rw http.ResponseWriter, rq *http.Request) { + fmt.Println("Отрабатывает метод", rq.Method) + // Получаем короткий URL из запроса + shortURL := rq.URL.String()[1:] + fmt.Println(shortURL) + + fmt.Println(urls) + + // Если URL уже имеется в хранилище, возвращем в браузер ответ и делаем редирект + if value, ok := urls[shortURL]; ok { + rw.Header().Set("Location", value) + rw.WriteHeader(307) + } else { + rw.Header().Set("Location", "URL not found") + rw.WriteHeader(400) + } + +} + +// Функция кодирования URL в сокращенный вид +func encodeURL(url string) (string, error) { + if url != "" { + var shortURL string + // кодируем URL по алгоритму base64 и сокращаем строку до 6 символов + fmt.Println("Закодированная ссылка =", base64.StdEncoding.EncodeToString([]byte(url))) + start := len(base64.StdEncoding.EncodeToString([]byte(url))) + shortURL = base64.StdEncoding.EncodeToString([]byte(url))[start-6:] + fmt.Println("Короткая ссылка =", shortURL) + return shortURL, nil + } else { + return "", errors.New("URL is empty") + } +} + +// Функция декодирования URL в адрес полной длины +func decodeURL(shortURL string) (string, error) { + // Ищем shortUrl в хранилище как ключ, если есть, позвращаем значение из мапы по данному ключу + if value, ok := urls[shortURL]; ok { + return value, nil + } + return "", errors.New("short URL not foud") +} \ No newline at end of file From af59f8234ea94b6f5e8ffce936fffd86fce139f3 Mon Sep 17 00:00:00 2001 From: Evgeny Gavriluk Date: Mon, 16 Oct 2023 18:58:37 +0300 Subject: [PATCH 2/8] add go.mod --- go.mod | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 go.mod diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..5ea6b28 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/evgenygavriluk/go-musthave-shortener-tpl + +go 1.21.3 From bf8969142b3b785583097aae97627d7c5f4f2b5e Mon Sep 17 00:00:00 2001 From: Evgeny Gavriluk Date: Mon, 16 Oct 2023 19:06:10 +0300 Subject: [PATCH 3/8] Iteration 2. testing HTTP saerver --- cmd/shortener/main_test.go | 105 +++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 cmd/shortener/main_test.go diff --git a/cmd/shortener/main_test.go b/cmd/shortener/main_test.go new file mode 100644 index 0000000..e2f841e --- /dev/null +++ b/cmd/shortener/main_test.go @@ -0,0 +1,105 @@ +package main + +import ( + "github.com/stretchr/testify/assert" + "net/http" + "net/http/httptest" + "testing" + "strings" + "fmt" +) + +func TestHandlerPost(t *testing.T){ + urls = make(map[string]string) + + type want struct { + code int + } + tests := []struct { + name string + body string + want want + }{ + { + name: "post test 1. body doesn't consist of data", + body: "", + want: want{ + code: 400, + }, + }, + { + name: "post test 2. body consist of data", + body: "http://ya.ru", + want: want{ + code: 201, + }, + + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + fmt.Printf("\n\nTest %v Body %v\n", test.name, test.body) + body := strings.NewReader(test.body) + request := httptest.NewRequest(http.MethodPost, "/", body) + w := httptest.NewRecorder() + handlerPost(w, request) + + res := w.Result() + fmt.Printf("want code = %d StatusCode %d\n", test.want.code, res.StatusCode) + assert.Equal(t, test.want.code, res.StatusCode) + }) + } + +} + +func TestHandlerGet(t *testing.T){ + type want struct { + code int + } + tests := []struct { + name string + body string + want want + }{ + { + name: "get test 1. body doesn't consist of data", + body: "", + want: want{ + code: 400, + }, + }, + { + name: "get test 2. body consist of data", + body: "http://ya.ru", + want: want{ + code: 307, + }, + + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + var addr string + if test.body == "/"{ + addr ="" + } else { + for k, v := range urls { + if v == test.body { + addr = k + } + } + } + fmt.Printf("\n\nTest %v Body %v Addr %v\n", test.name, test.body, addr) + request := httptest.NewRequest(http.MethodGet, "/"+addr, nil) + w := httptest.NewRecorder() + handlerGet(w, request) + + res := w.Result() + fmt.Printf("want code = %d StatusCode %d\n", test.want.code, res.StatusCode) + assert.Equal(t, test.want.code, res.StatusCode) + }) + } + +} \ No newline at end of file From 78f96c2d0cef041353e8cb5b20236939b3cb418b Mon Sep 17 00:00:00 2001 From: Evgeny Gavriluk Date: Mon, 16 Oct 2023 19:19:27 +0300 Subject: [PATCH 4/8] iter2 updata --- go.mod | 8 ++++++++ go.sum | 10 ++++++++++ 2 files changed, 18 insertions(+) create mode 100644 go.sum diff --git a/go.mod b/go.mod index 5ea6b28..51f170c 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,11 @@ module github.com/evgenygavriluk/go-musthave-shortener-tpl go 1.21.3 + +require github.com/stretchr/testify v1.8.4 + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..fa4b6e6 --- /dev/null +++ b/go.sum @@ -0,0 +1,10 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From aa1e3c46bddd4de2a4980e48c6c2ab842aea2c89 Mon Sep 17 00:00:00 2001 From: Evgeny Gavriluk Date: Mon, 16 Oct 2023 19:28:28 +0300 Subject: [PATCH 5/8] added close response --- cmd/shortener/main_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmd/shortener/main_test.go b/cmd/shortener/main_test.go index e2f841e..8599821 100644 --- a/cmd/shortener/main_test.go +++ b/cmd/shortener/main_test.go @@ -46,6 +46,7 @@ func TestHandlerPost(t *testing.T){ handlerPost(w, request) res := w.Result() + defer res.Body.Close() fmt.Printf("want code = %d StatusCode %d\n", test.want.code, res.StatusCode) assert.Equal(t, test.want.code, res.StatusCode) }) @@ -97,6 +98,7 @@ func TestHandlerGet(t *testing.T){ handlerGet(w, request) res := w.Result() + defer res.Body.Close() fmt.Printf("want code = %d StatusCode %d\n", test.want.code, res.StatusCode) assert.Equal(t, test.want.code, res.StatusCode) }) From f1d41f7757a00a890d787d51c33a8ed9434014ca Mon Sep 17 00:00:00 2001 From: Evgeny Gavriluk Date: Mon, 16 Oct 2023 19:43:46 +0300 Subject: [PATCH 6/8] Iteration 3. Refactoring server --- cmd/shortener/main.go | 28 ++++++++++------------------ go.mod | 5 ++++- go.sum | 2 ++ 3 files changed, 16 insertions(+), 19 deletions(-) diff --git a/cmd/shortener/main.go b/cmd/shortener/main.go index 82df0cd..a518398 100644 --- a/cmd/shortener/main.go +++ b/cmd/shortener/main.go @@ -6,6 +6,8 @@ import ( "fmt" "net/http" "io" + "github.com/go-chi/chi" + "log" ) var urls map[string]string // хранилище ссылок @@ -14,27 +16,17 @@ func main() { urls = make(map[string]string) - mux := http.NewServeMux() - mux.HandleFunc("/", checkMethod) + r := chi.NewRouter() + r.Post("/", handlerPost) + r.Get("/{link}", handlerGet) + fmt.Println("Server is starter") - err := http.ListenAndServe(":8080", mux) - if err != nil { - panic(err) - } -} + log.Fatal(http.ListenAndServe(":8080", r)) -// Роутер перенаправляет на обработчик запросов POST или GET -func checkMethod(rw http.ResponseWriter, rq *http.Request) { - fmt.Println("Пришел метод", rq.Method) - if rq.Method == http.MethodPost { - handlerPost(rw, rq) - } - if rq.Method == http.MethodGet { - handlerGet(rw, rq) - } } + // Обрабатывает POST-запрос. Возвращает заголовок со статусом 201, если результат Ок func handlerPost(rw http.ResponseWriter, rq *http.Request) { fmt.Println("Отрабатывает метод", rq.Method) @@ -66,7 +58,7 @@ func handlerPost(rw http.ResponseWriter, rq *http.Request) { func handlerGet(rw http.ResponseWriter, rq *http.Request) { fmt.Println("Отрабатывает метод", rq.Method) // Получаем короткий URL из запроса - shortURL := rq.URL.String()[1:] + shortURL := chi.URLParam(rq, "link") fmt.Println(shortURL) fmt.Println(urls) @@ -104,4 +96,4 @@ func decodeURL(shortURL string) (string, error) { return value, nil } return "", errors.New("short URL not foud") -} \ No newline at end of file +} diff --git a/go.mod b/go.mod index 51f170c..395fddd 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,10 @@ module github.com/evgenygavriluk/go-musthave-shortener-tpl go 1.21.3 -require github.com/stretchr/testify v1.8.4 +require ( + github.com/go-chi/chi v1.5.5 + github.com/stretchr/testify v1.8.4 +) require ( github.com/davecgh/go-spew v1.1.1 // indirect diff --git a/go.sum b/go.sum index fa4b6e6..56f0749 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-chi/chi v1.5.5 h1:vOB/HbEMt9QqBqErz07QehcOKHaWFtuj87tTDVz2qXE= +github.com/go-chi/chi v1.5.5/go.mod h1:C9JqLr3tIYjDOZpzn+BCuxY8z8vmca43EeMgyZt7irw= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= From d3461069a898ff6d764dacc0533a2d4bfaadd3a3 Mon Sep 17 00:00:00 2001 From: Evgeny Gavriluk Date: Tue, 17 Oct 2023 00:29:09 +0300 Subject: [PATCH 7/8] iter3 testing --- cmd/shortener/main.go | 6 ++---- cmd/shortener/main_test.go | 10 +++++----- go.mod | 1 + go.sum | 2 ++ 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/cmd/shortener/main.go b/cmd/shortener/main.go index a518398..5072b15 100644 --- a/cmd/shortener/main.go +++ b/cmd/shortener/main.go @@ -6,7 +6,7 @@ import ( "fmt" "net/http" "io" - "github.com/go-chi/chi" + "github.com/go-chi/chi/v5" "log" ) @@ -58,9 +58,7 @@ func handlerPost(rw http.ResponseWriter, rq *http.Request) { func handlerGet(rw http.ResponseWriter, rq *http.Request) { fmt.Println("Отрабатывает метод", rq.Method) // Получаем короткий URL из запроса - shortURL := chi.URLParam(rq, "link") - fmt.Println(shortURL) - + shortURL := rq.URL.String()[1:] fmt.Println(urls) // Если URL уже имеется в хранилище, возвращем в браузер ответ и делаем редирект diff --git a/cmd/shortener/main_test.go b/cmd/shortener/main_test.go index 8599821..76ac9bd 100644 --- a/cmd/shortener/main_test.go +++ b/cmd/shortener/main_test.go @@ -22,14 +22,14 @@ func TestHandlerPost(t *testing.T){ }{ { name: "post test 1. body doesn't consist of data", - body: "", + param: "", want: want{ code: 400, }, }, { name: "post test 2. body consist of data", - body: "http://ya.ru", + param: "http://ya.ru", want: want{ code: 201, }, @@ -39,9 +39,9 @@ func TestHandlerPost(t *testing.T){ for _, test := range tests { t.Run(test.name, func(t *testing.T) { - fmt.Printf("\n\nTest %v Body %v\n", test.name, test.body) - body := strings.NewReader(test.body) - request := httptest.NewRequest(http.MethodPost, "/", body) + fmt.Printf("\n\nTest %v Body %v\n", test.name, test.param) + param := strings.NewReader(test.body) + request := httptest.NewRequest(http.MethodPost, "/", param) w := httptest.NewRecorder() handlerPost(w, request) diff --git a/go.mod b/go.mod index 395fddd..b8c4047 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( require ( github.com/davecgh/go-spew v1.1.1 // indirect + github.com/go-chi/chi/v5 v5.0.10 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 56f0749..230affe 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-chi/chi v1.5.5 h1:vOB/HbEMt9QqBqErz07QehcOKHaWFtuj87tTDVz2qXE= github.com/go-chi/chi v1.5.5/go.mod h1:C9JqLr3tIYjDOZpzn+BCuxY8z8vmca43EeMgyZt7irw= +github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk= +github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= From b8bb2f34c07bf7a909ea2a99b0ef11ab164df1cb Mon Sep 17 00:00:00 2001 From: Evgeny Gavriluk Date: Tue, 17 Oct 2023 00:34:26 +0300 Subject: [PATCH 8/8] iter3. 2 --- cmd/shortener/main_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/shortener/main_test.go b/cmd/shortener/main_test.go index 76ac9bd..2a97e90 100644 --- a/cmd/shortener/main_test.go +++ b/cmd/shortener/main_test.go @@ -17,7 +17,7 @@ func TestHandlerPost(t *testing.T){ } tests := []struct { name string - body string + param string want want }{ { @@ -40,7 +40,7 @@ func TestHandlerPost(t *testing.T){ for _, test := range tests { t.Run(test.name, func(t *testing.T) { fmt.Printf("\n\nTest %v Body %v\n", test.name, test.param) - param := strings.NewReader(test.body) + param := strings.NewReader(test.param) request := httptest.NewRequest(http.MethodPost, "/", param) w := httptest.NewRecorder() handlerPost(w, request)