The standard library packages exist in the first group.
Then Third — party libs.
At the end of the Imports from your project.
The standard library packages exist in the first group.
Then Third — party libs.
At the end of the Imports from your project.
You can use the go env command to view the values of these variables on your machine:
$ go env
...
GOARCH="amd64"
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
...
Here’s the command you need to run to compile your Go project for a 64-bit Windows machine:
$ GOOS=windows GOARCH=amd64 go build -o bin/app-amd64.exe app.go
In this scenario, GOOS is windows, and GOARCH is amd64 indicating a 64-bit architecture. If you need to support a 32-bit architecture, all you need to do is change GOARCH to 386.
$ GOOS=windows GOARCH=386 go build -o bin/app-386.exe app.go
The GOARCH values for Windows are also valid for macOS, but in this case the required GOOS value is darwin:
# 64-bit
$ GOOS=darwin GOARCH=amd64 go build -o bin/app-amd64-darwin app.go
# 32-bit
$ GOOS=darwin GOARCH=386 go build -o bin/app-386-darwin app.go
To build your Go program for Linux, use linux as the value of GOOS and the appropriate GOARCH value for your target CPU architecture:
# 64-bit
$ GOOS=linux GOARCH=amd64 go build -o bin/app-amd64-linux app.go
# 32-bit
$ GOOS=linux GOARCH=386 go build -o bin/app-386-linux app.go
Install all Go project dependencies in one command
go get ./...
downloads all the dependencies
go get -u -v -f all
проверка Луна
код луна
https://go.dev/play/p/S_nrTTrk0Wq
package main
import (
"fmt"
"github.com/theplant/luhn"
)
func main() {
fmt.Println(
luhn.Valid(6174570601580),
luhn.Valid(422466257468622),
luhn.Valid(2352238521358),
luhn.Valid(7162683784855),
)
}
Using JWT for Authentication in a Golang Application
https://developer.vonage.com/blog/2020/03/13/using-jwt-for-authentication-in-a-golang-application-dr
https://disk.yandex.ru/d/IzZ3Y6P_EAAC6w
https://github.com/victorsteven/jwt-best-practices
package mux
import (
"compress/gzip"
"fmt"
"log"
"mime"
"net/http"
"path/filepath"
"strings"
)
func GzipAutoMiddleware(hf http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
accept := r.Header.Get("Accept-Encoding")
content := r.Header.Get("Content-Encoding")
if strings.Contains(content, "gzip") {
reader, e := gzip.NewReader(r.Body)
if e != nil {
e = fmt.Errorf("reading gzip body failed:%w", e)
log.Println(e)
http.Error(w, e.Error(), http.StatusBadRequest)
return
}
r.Body = reader
}
if strings.Contains(accept, "gzip") {
ext := filepath.Ext(r.RequestURI)
mime := mime.TypeByExtension(ext)
if r.RequestURI == "/" || strings.HasPrefix(mime, "text/") || ext == ".json" || ext == ".js" {
w.Header().Set("Content-Encoding", "gzip")
gw := gzip.NewWriter(w)
defer gw.Flush()
defer gw.Close()
w = &ResponseWriterBuf{
Rw: w,
Writer: gw,
}
}
}
hf(w, r)
}
}
Here’s an example of parsing into a struct:
type App struct { Id string `json:"id"` Title string `json:"title"` } data := []byte(` { "id": "k34rAT4", "title": "My Awesome App" } `) var app App err := json.Unmarshal(data, &app)
What you’re left with is app populated with the parsed JSON that was in data. You’ll also notice that the go term for parsing json is “Unmarshalling”.
Outputting from a struct works exactly as parsing but in reverse:
data, err := json.Marshal(app)
As with all structs in Go, it’s important to remember that only fields with a capital first letter are visible to external programs like the JSON Marshaller.
You can get rid of the JsonType as well and just use a slice:
package main
import (
"encoding/json"
"log"
)
func main() {
dataJson := `["1","2","3"]`
var arr []string
_ = json.Unmarshal([]byte(dataJson), &arr)
log.Printf("Unmarshaled: %v", arr)
}
// prints out:
// 2009/11/10 23:00:00 Unmarshaled: [1 2 3]
Code on play: https://play.golang.org/p/GNWlylavam
Пример тестирование API HTTP
package apiserver
import (
"bytes"
"encoding/json"
"fmt"
"github.com/stretchr/testify/assert"
"net/http"
"net/http/httptest"
"rest_api/internal/app/model"
"rest_api/internal/app/store/teststore"
"testing"
)
func TestServer_HandleCreateUser(t *testing.T) {
s := newServer(teststore.New())
testCases := []struct {
name string
payload interface{}
expectedCode int
}{
{
name: "valid",
payload: map[string]interface{}{
"name": "Name",
"email": "current@mail.com",
"password": "123456",
},
expectedCode: http.StatusCreated,
},
{
name: "empty payload",
payload: "invalid",
expectedCode: http.StatusBadRequest,
},
{
name: "invalid email",
payload: map[string]interface{}{
"name": "Name",
"email": "nenormalmail",
"password": "12345",
},
expectedCode: http.StatusUnprocessableEntity,
},
{
name: "invalid password",
payload: map[string]interface{}{
"name": "Name",
"email": "normal@mail.com",
"password":"12345",
},
expectedCode: http.StatusUnprocessableEntity,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
b := &bytes.Buffer{}
json.NewEncoder(b).Encode(tc.payload)
rec := httptest.NewRecorder()
req, _ := http.NewRequest(http.MethodPost, "/create", b)
s.ServeHTTP(rec, req)
assert.Equal(t, tc.expectedCode, rec.Code)
})
}
}
func TestServer_HandleAuthorizeUser(t *testing.T) {
s := newServer(teststore.New())
testCases := []struct{
name string
payload interface{}
expectedCode int
}{
{
name: "valid",
payload: map[string]interface{}{
"email": "test@example.com",
"password": "password",
},
expectedCode: http.StatusOK,
},
{
name: "invalid payload",
payload: "invalid",
expectedCode: http.StatusBadRequest,
},
{
name: "invalid user",
payload: map[string]interface{}{
"email": "test@example.com",
"password": "",
},
expectedCode: http.StatusForbidden,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
user := map[string]interface{}{
"name": "User",
"email": "test@example.com",
"password": "password",
}
resp := struct {
Token string `json:"token"`
}{}
b := &bytes.Buffer{}
json.NewEncoder(b).Encode(user)
rec := httptest.NewRecorder()
req, _ := http.NewRequest(http.MethodPost, "/create", b)
s.ServeHTTP(rec, req)
json.NewEncoder(b).Encode(tc.payload)
rec = httptest.NewRecorder()
req, _ = http.NewRequest(http.MethodPost, "/authorize", b)
s.ServeHTTP(rec, req)
json.NewDecoder(rec.Body).Decode(resp)
recToken := resp.Token
assert.Equal(t, tc.expectedCode, rec.Code)
assert.NotNil(t, recToken)
})
}
}
func TestServer_HandleCreateArticle(t *testing.T) {
s := newServer(teststore.New())
testCases := []struct{
name string
payload interface{}
expectedCode int
}{
{
name: "valid",
payload: map[string]interface{}{
"article_header": "Test Article",
"article_text": "Article test text",
"author_id": 1,
},
expectedCode: http.StatusCreated,
},
{
name: "invalid",
payload: "invalid",
expectedCode: http.StatusBadRequest,
},
{
name: "invalid article text",
payload: map[string]interface{}{
"article_header": "Test Article",
"article_text": 7,
"author_id": 1,
},
expectedCode: http.StatusBadRequest,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
us := map[string]interface{}{
"name": "User",
"email": "user@mail.com",
"password": "123456",
}
resp := &struct {
User *model.User `json:"user"`
Token string `json:"token"`
}{}
b := &bytes.Buffer{}
json.NewEncoder(b).Encode(us)
rec := httptest.NewRecorder()
req, _ := http.NewRequest(http.MethodPost, "/create", b)
s.ServeHTTP(rec, req)
json.NewDecoder(rec.Body).Decode(resp)
token := fmt.Sprintf("Baerer %s", resp.Token)
json.NewEncoder(b).Encode(tc.payload)
req, _ = http.NewRequest(http.MethodPost, "/private/create/article", b)
rec = httptest.NewRecorder()
req.Header.Add("Authorization", token)
s.ServeHTTP(rec, req)
assert.Equal(t, tc.expectedCode, rec.Code)
})
}
}
func TestServer_HandleFindArticleByHeading(t *testing.T) {
ts := teststore.New()
ts.Article().CreateArticle(model.TestArticle(t, 5))
s := newServer(ts)
testCases := []struct{
name string
payload interface{}
expectedCode int
}{
{
name: "valid",
payload: map[string]interface{}{
"article_heading": "TestArticle",
},
expectedCode: http.StatusOK,
},
{
name: "invalid article header",
payload: map[string]interface{}{
"article_heading": "Article",
},
expectedCode: http.StatusUnprocessableEntity,
},
{
name: "invalid request",
payload: map[string]interface{}{
"article_heading": 1,
},
expectedCode: http.StatusBadRequest,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
b := &bytes.Buffer{}
json.NewEncoder(b).Encode(tc.payload)
rec := httptest.NewRecorder()
req, _ := http.NewRequest(http.MethodGet, "/find/article", b)
s.ServeHTTP(rec, req)
assert.Equal(t, tc.expectedCode, rec.Code)
})
}
}
func TestServer_HandleChangeArticle(t *testing.T) {
ts := teststore.New()
article := model.TestArticle(t, 5)
ts.Article().CreateArticle(article)
s := newServer(ts)
testCases := []struct{
name string
payload interface{}
expectedCode int
}{
{
name: "valid",
payload: map[string]interface{}{
"id" : article.ID,
"article_header": "Updated TestArticle",
"article_text": "updated article text",
},
expectedCode: http.StatusOK,
},
{
name: "invalid",
payload: "invalid",
expectedCode: http.StatusBadRequest,
},
{
name: "invalid id",
payload: map[string]interface{}{
"id" : 1,
"article_header": "Updated TestArticle",
"article_text": "updated article text",
},
expectedCode: http.StatusUnprocessableEntity,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
us := map[string]interface{}{
"name": "User",
"email": "user@mail.com",
"password": "123456",
}
resp := &struct {
User *model.User `json:"user"`
Token string `json:"token"`
}{}
b := &bytes.Buffer{}
json.NewEncoder(b).Encode(us)
rec := httptest.NewRecorder()
req, _ := http.NewRequest(http.MethodPost, "/create", b)
s.ServeHTTP(rec, req)
json.NewDecoder(rec.Body).Decode(resp)
token := fmt.Sprintf("Baerer %s", resp.Token)
json.NewEncoder(b).Encode(tc.payload)
req, _ = http.NewRequest(http.MethodPut, "/private/change/article", b)
rec = httptest.NewRecorder()
req.Header.Add("Authorization", token)
s.ServeHTTP(rec, req)
assert.Equal(t, tc.expectedCode, rec.Code)
})
}
}
func TestServer_HandleDeleteArticle(t *testing.T) {
ts := teststore.New()
article := model.TestArticle(t, 5)
ts.Article().CreateArticle(article)
s := newServer(ts)
testCases := []struct{
name string
payload interface{}
expectedCode int
}{
{
name: "valid",
payload: map[string]interface{}{
"id" : article.ID,
},
expectedCode: http.StatusOK,
},
{
name: "invalid",
payload: "invalid",
expectedCode: http.StatusBadRequest,
},
{
name: "invalid id",
payload: map[string]interface{}{
"id" : 1,
},
expectedCode: http.StatusUnprocessableEntity,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
us := map[string]interface{}{
"name": "User",
"email": "user@mail.com",
"password": "123456",
}
resp := &struct {
User *model.User `json:"user"`
Token string `json:"token"`
}{}
b := &bytes.Buffer{}
json.NewEncoder(b).Encode(us)
rec := httptest.NewRecorder()
req, _ := http.NewRequest(http.MethodPost, "/create", b)
s.ServeHTTP(rec, req)
json.NewDecoder(rec.Body).Decode(resp)
token := fmt.Sprintf("Baerer %s", resp.Token)
json.NewEncoder(b).Encode(tc.payload)
req, _ = http.NewRequest(http.MethodDelete, "/private/delete/article", b)
rec = httptest.NewRecorder()
req.Header.Add("Authorization", token)
s.ServeHTTP(rec, req)
assert.Equal(t, tc.expectedCode, rec.Code)
})
}
}
https://github.com/backspacesh/notebook_api/blob/5bdd97a7b98f85a84d6af4bb51da9d128a520384/internal/app/apiserver/server_internal_test.go