package main import ( "bytes" "context" "encoding/json" "fmt" "github.com/caarlos0/env/v8" "github.com/google/uuid" "github.com/gorilla/mux" "gorm.io/driver/postgres" "gorm.io/gorm" "log" "net/http" "os" "os/signal" "syscall" ) type Сonfig struct { Port string `env:"USER_HTTP_ADDR" envDefault:"13999"` PgPort string `env:"PG_PORT" envDefault:"5432"` PgHost string `env:"PG_HOST" envDefault:"bd1"` PgDBName string `env:"PG_DB_NAME" envDefault:"service1"` PgUser string `env:"PG_USER" envDefault:"postgres"` PgPwd string `env:"PG_PWD" envDefault:"159753"` } func main() { cfg := Сonfig{} if err := env.Parse(&cfg); err != nil { log.Fatalf("failed to retrieve env variables, %v", err) } if err := Run(cfg); err != nil { log.Fatal("error running grpc server ", err) } } type Clerc struct { Id uuid.UUID `json:"id" gorm:"type:uuid;default:uuid_generate_v4();primaryKey"` Name string `json:"name" gorm:"name"` Post string `json:"post" gorm:"post"` OfficeId uuid.UUID `json:"office_id" gorm:"office_id"` } func InitDb(cfg Сonfig) (*gorm.DB, error) { dsn := fmt.Sprintf( "host=%s user=%s password=%s dbname=%s port=%s sslmode=disable", cfg.PgHost, cfg.PgUser, cfg.PgPwd, cfg.PgDBName, cfg.PgPort, ) db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{}) if err != nil { log.Fatal("Cannot to Connect DataBase", err) } db.AutoMigrate(&Clerc{}) return gorm.Open(postgres.Open(dsn), &gorm.Config{}) } type ClercRepository interface { Create(ctx context.Context, c *Clerc) error Get(ctx context.Context, id uuid.UUID) (*Clerc, error) GetList(ctx context.Context) ([]*Clerc, error) Update(ctx context.Context, c *Clerc) error Delete(ctx context.Context, id uuid.UUID) error } type ClercStorage struct { db *gorm.DB } func NewCs(db *gorm.DB) *ClercStorage { return &ClercStorage{ db: db, } } func (cs *ClercStorage) Create(ctx context.Context, clerc *Clerc) error { return cs.db.WithContext(ctx).Create(clerc).Error } func (cs *ClercStorage) Get(ctx context.Context, id uuid.UUID) (*Clerc, error) { c := new(Clerc) err := cs.db.WithContext(ctx).First(c, id).Error return c, err } func (cs *ClercStorage) GetList(ctx context.Context) ([]*Clerc, error) { clercs := []*Clerc{} err := cs.db.WithContext(ctx).Find(&clercs).Error return clercs, err } func (cs *ClercStorage) Update(ctx context.Context, clerc *Clerc) error { return cs.db.WithContext(ctx).Save(clerc).Error } func (cs *ClercStorage) Delete(ctx context.Context, id uuid.UUID) error { c := new(Clerc) return cs.db.WithContext(ctx).Where("id = ?", id).Delete(c).Error } type Service struct { clercrep ClercRepository config Сonfig } func NewServ(cfg Сonfig, clercrep ClercRepository) *Service { return &Service{ config: cfg, clercrep: clercrep, } } func (s *Service) GetHandler() http.Handler { router := mux.NewRouter() router.HandleFunc("/service1/clerc/post", s.Post).Methods(http.MethodPost) router.HandleFunc("/service1/clerc/get", s.Get).Methods(http.MethodGet) router.HandleFunc("/service1/clerc/getall", s.GetAll).Methods(http.MethodGet) router.HandleFunc("/service1/clerc/put", s.Put).Methods(http.MethodPut) router.HandleFunc("/service1/clerc/delete", s.Delete).Methods(http.MethodDelete) return router } type PostRequest struct { Name string `json:"name"` Post string `json:"post"` OfficeId string `json:"office_id"` } func (s *Service) Post(w http.ResponseWriter, r *http.Request) { req := &PostRequest{} if err := json.NewDecoder(r.Body).Decode(req); err != nil { log.Println("Не удалось разкодировать запрос", err) w.WriteHeader(http.StatusBadRequest) return } officeUuid, err := uuid.Parse(req.OfficeId) if err != nil { log.Println("Не удалось конвертировать строку в uuid", err) w.WriteHeader(http.StatusBadRequest) return } c := Clerc{ Name: req.Name, Post: req.Post, OfficeId: officeUuid, } err = s.clercrep.Create(r.Context(), &c) if err != nil { log.Println("Не удалось создать клерка", err) w.WriteHeader(http.StatusInternalServerError) return } log.Println("Пытаемся передать id клерка на второй сервис") url := "http://nginx/service2/office/patch" data := map[string]interface{}{ "office_id": c.OfficeId.String(), "clerc_id": c.Id.String(), } log.Println(c.OfficeId.String(), c.Id.String()) payload, err := json.Marshal(data) if err != nil { log.Println("Не удалось закодировать данные в json") w.WriteHeader(http.StatusInternalServerError) return } request, err := http.NewRequest("PATCH", url, bytes.NewBuffer(payload)) if err != nil { log.Println("Не удалось создать patch запрос") w.WriteHeader(http.StatusInternalServerError) return } client := &http.Client{} resp, err := client.Do(request) if err != nil { log.Println("Не удалось отправить patch запрос") return } defer resp.Body.Close() w.WriteHeader(http.StatusCreated) w.Header().Set("Content-Type", "application/json") _ = json.NewEncoder(w).Encode(c) } func (s *Service) Get(w http.ResponseWriter, r *http.Request) { id := r.URL.Query().Get("id") uuid, err := uuid.Parse(id) if err != nil { log.Println("Не удалось конвертировать строку в uuid", err) w.WriteHeader(http.StatusBadRequest) return } c, err := s.clercrep.Get(r.Context(), uuid) if err != nil { log.Println("Не удалось получить запись клерка", err) w.WriteHeader(http.StatusNotFound) return } w.WriteHeader(http.StatusOK) w.Header().Set("Content-Type", "application/json") _ = json.NewEncoder(w).Encode(c) } func (s *Service) GetAll(w http.ResponseWriter, r *http.Request) { clercs, err := s.clercrep.GetList(r.Context()) if err != nil { log.Println("Не удалось получить записи клерков из бд", err) w.WriteHeader(http.StatusNotFound) return } w.WriteHeader(http.StatusOK) w.Header().Set("Content-Type", "application/json") _ = json.NewEncoder(w).Encode(clercs) } func (s *Service) Put(w http.ResponseWriter, r *http.Request) { req := &Clerc{} if err := json.NewDecoder(r.Body).Decode(req); err != nil { log.Println("Не удалось разкодировать запрос", err) w.WriteHeader(http.StatusBadRequest) return } err := s.clercrep.Update(r.Context(), req) if err != nil { log.Println("Не удалось обновить запись о пользователе", err) w.WriteHeader(http.StatusNotFound) return } c, err := s.clercrep.Get(r.Context(), req.Id) if err != nil { log.Println("Не удалось получить запись пользователя из бд", err) w.WriteHeader(http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) w.Header().Set("Content-Type", "application/json") _ = json.NewEncoder(w).Encode(c) } type DeleteRequest struct { Id string `json:"id"` } func (s *Service) Delete(w http.ResponseWriter, r *http.Request) { req := &DeleteRequest{} if err := json.NewDecoder(r.Body).Decode(req); err != nil { log.Println("Не удалось разкодировать запрос", err) w.WriteHeader(http.StatusBadRequest) return } uuid, err := uuid.Parse(req.Id) if err != nil { log.Println("Не удалось конвертировать строку в uuid", err) w.WriteHeader(http.StatusBadRequest) return } err = s.clercrep.Delete(r.Context(), uuid) if err != nil { log.Println("Не удалось удалить запись о пользователе", err) w.WriteHeader(http.StatusNotFound) return } w.WriteHeader(http.StatusOK) } func Run(cfg Сonfig) error { db, err := InitDb(cfg) if err != nil { return err } serv := NewServ(cfg, NewCs(db)) s := &http.Server{ Addr: ":13999", //"0.0.0.0:%d", cfg.Port), Handler: serv.GetHandler(), } s.SetKeepAlivesEnabled(true) ctx, cancel := context.WithCancel(context.Background()) go func() { log.Printf("starting http server at %d", cfg.Port) if err := s.ListenAndServe(); err != nil { log.Fatal(err) } }() gracefullyShutdown(ctx, cancel, s) return nil } func gracefullyShutdown(ctx context.Context, cancel context.CancelFunc, server *http.Server) { ch := make(chan os.Signal, 1) signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM) defer signal.Stop(ch) <-ch if err := server.Shutdown(ctx); err != nil { log.Print(err) } cancel() }