Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Cómo crear un Microservicio en Go

Cómo crear un Microservicio en Go

Friends of Go

November 22, 2019
Tweet

More Decks by Friends of Go

Other Decks in Programming

Transcript

  1. CÓMO CREAR UN MICROSERVICIO EN GO viernes, 22 de noviembre

    de 2019 Joan López de la Franca @joanjan14 Adrián Pérez @adrianpgl
  2. Para seguir la formación y compartir material utilizaremos el Slack

    de Friends of Go, para ello deberéis uniros en el siguiente enlace: http://bit.ly/commit-slack-fogo Uniros al canal #commitconf2019 CÓMO CREAR UN MICROSERVICIO EN GO COMUNICACIÓN DURANTE EL WORKSHOP
  3. ‣ Clona el repositorio: git clone https://github.com/friendsofgo/workshop-microservices.git ‣ Obtén tu

    licencia de Kafka-Lense (https://lenses.io/downloads/lenses/) ‣ Haz pull de las siguientes imágenes de docker: docker pull mongo:3.4 docker pull lensesio/box:3.0.2 ‣ Baja Robo3T (https://robomongo.org/download) CÓMO CREAR UN MICROSERVICIO EN GO ANTES DE NADA
  4. ‣ ¿Qué es un microservicio?¿Microservicio para todo? ‣ ¿Por qué

    Go? ‣ ¿Qué vamos a montar? ‣ ¿Por dónde empiezo? CÓMO CREAR UN MICROSERVICIO EN GO AGENDA: SPRINT 1
  5. ‣ Gran mantenibilidad, testeabilidad, escalabilidad ‣ Desacoplado ‣ Deploy independiente

    ‣ Pensado para cumplir funciones concretas del negocio ‣ Puede ser gestionado por un equipo pequeño TÍTULO DE LA PRESENTACIÓN ARQUITECTURA DE MICROSERVICIOS
  6. ‣ Es muy ligero ‣ Es muy rápido ‣ Librería

    estándar potente para escribir web services ‣ Tiene concurrencia de serie CÓMO CREAR UN MICROSERVICIO EN GO ¿QUÉ APORTA GO, SOBRE OTROS LENGUAJES?
  7. CÓMO CREAR UN MICROSERVICIO EN GO “COUNTERS” -LA APLICACIÓN- ‣

    Registro e inicio de sesión (usuarios) ‣ Crear e incrementar (contadores) ‣ Obtener estadísticas de uso (informes) ‣ Sistema de widgets (widgets) ‣ Sistema de facturación (facturación) ‣ Y más…
  8. NUESTRA ARQUITECTURA CÓMO CREAR UN MICROSERVICIO EN GO COUNTERS CLIENTE

    USERS PAYMENTS … SISTEMA DISTRIBUIDO DE EVENTOS
  9. ‣ cmd/ ‣ internal/ y/o pkg/ ‣ kit CÓMO CREAR

    UN MICROSERVICIO EN GO ¿QUÉ NOS ENCONTRAMOS EN NUESTRO PROYECTO?
  10. ‣ Docker ‣ Package Oriented Design ‣ Gorilla Mux ‣

    Mongo DB ‣ Kafka CÓMO CREAR UN MICROSERVICIO EN GO ¿QUÉ VAMOS A UTILIZAR?
  11. ‣ Utilizar la librería estándar para crear un server http

    ‣ Crear un endpoint GET /health ‣ Devolver 200 OK en el header de cuando se llama a /health ‣ Imprimir en JSON {“data”: {“kind”: “health”, “message”: “everything is fine”} } CÓMO CREAR UN MICROSERVICIO EN GO ¿QUÉ VAS A HACER EN ESTE SPRINT?
  12. LEVANTAR UN SERVIDOR CÓMO CREAR UN MICROSERVICIO EN GO srv

    := http.NewServeMux() srv.HandleFunc("/endpoint", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) w.Write([]byte("hola mundo")) }) log.Fatal(http.ListenAndServe(":3000", srv))
  13. JSON MARSHAL CÓMO CREAR UN MICROSERVICIO EN GO type response

    struct { MyField string `json:"my_field"` MyOtherField int `json:"my_other_field,omitempty"` } r := response{MyField: "hello world"} b, err := json.Marshal(r) if err != nil { return err }
  14. ‣ Refactorizar mi Servidor HTTP con Gorilla Mux ‣ Utilización

    de middlewares en mi servidor ‣ Testeando nuestros handlers CÓMO CREAR UN MICROSERVICIO EN GO AGENDA: SPRINT 2
  15. CREAR UN SERVIDOR CON GORILLA MUX CÓMO CREAR UN MICROSERVICIO

    EN GO r := mux.NewRouter() r.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) w.Write([]byte("hello world")) }) log.Fatal(http.ListenAndServe(":3000", r))
  16. TESTEANDO NUESTRO HEALTH HANDLER CÓMO CREAR UN MICROSERVICIO EN GO

    func TestServer_healthHandler(t *testing.T) { req, err := http.NewRequest("GET", "/health", nil) if err != nil { t.Fatalf("could not created request: %v", err) } … }
  17. TESTEANDO NUESTRO HEALTH HANDLER CÓMO CREAR UN MICROSERVICIO EN GO

    func TestServer_healthHandler(t *testing.T) { ... rec := httptest.NewRecorder() srv := NewServer(context.Background(), "", 0, &creatingmock.Service{}, &log.Logger{}) srv.healthHandler(context.Background()).ServeHTTP(rec, req) res := rec.Result() defer res.Body.Close() ... }
  18. TESTEANDO NUESTRO HEALTH HANDLER CÓMO CREAR UN MICROSERVICIO EN GO

    func TestServer_healthHandler(t *testing.T) { ... rec := httptest.NewRecorder() srv := NewServer(context.Background(), "", 0, &creatingmock.Service{}, &log.Logger{}) srv.healthHandler(context.Background()).ServeHTTP(rec, req) res := rec.Result() defer res.Body.Close() ... }
  19. TESTEANDO NUESTRO HEALTH HANDLER CÓMO CREAR UN MICROSERVICIO EN GO

    func TestServer_healthHandler(t *testing.T) { ... rec := httptest.NewRecorder() srv := NewServer(context.Background(), "", 0, &creatingmock.Service{}, &log.Logger{}) srv.healthHandler(context.Background()).ServeHTTP(rec, req) res := rec.Result() defer res.Body.Close() ... }
  20. TESTEANDO NUESTRO HEALTH HANDLER CÓMO CREAR UN MICROSERVICIO EN GO

    func TestServer_healthHandler(t *testing.T) { ... if res.StatusCode != http.StatusOK { t.Errorf("GET /health want %d, got: %d", http.StatusOK, res.StatusCode) } ... }
  21. TESTEANDO NUESTRO HEALTH HANDLER CÓMO CREAR UN MICROSERVICIO EN GO

    func TestServer_healthHandler(t *testing.T) { ... b, err := ioutil.ReadAll(res.Body) if err != nil { t.Fatalf("GET /health has a unreadble response; %v", err) } expectedResponse := `{"data":{"kind":"health","message":"everything is fine"}}` strResponse := string(b) if strResponse != expectedResponse { t.Errorf("GET /health want response %s, got: %s", expectedResponse, strResponse) } }
  22. MIDDLEWARE CÓMO CREAR UN MICROSERVICIO EN GO func loggerMiddleware(next http.Handler)

    http.Handler { return http.HandlerFunc( func(w http.ResponseWriter, r *http.Request) { path, _ := mux.CurrentRoute(r).GetPathTemplate() log.Printf("%s: %s\n", r.Method, path) next.ServeHTTP(w, r) }, ) }
  23. USANDO MIDDLEWARES CÓMO CREAR UN MICROSERVICIO EN GO r :=

    mux.NewRouter() r.Use(loggerMiddleware) r.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) w.Write([]byte("hello world")) }) log.Fatal(http.ListenAndServe(":3000", r))
  24. ‣ Refactorizar el servidor de la solución 1 usando Gorilla

    Mux ‣ Empezar a utilizar el logging middleware del fichero server/middleware.go ‣ Crear un middleware que logue el tiempo que ha tardado en ejecutarse nuestro handler ‣ Testear un nuevo handler, el cual se encarga de crear un nuevo contador (te damos el caso de uso hecho) CÓMO CREAR UN MICROSERVICIO EN GO ¿QUÉ VAS A HACER EN ESTE SPRINT?
  25. ‣ Leyendo eventos de otro microservicio ‣ Exponer nuestro propio

    endpoint ‣ Publicando eventos hacia otros microservicios ‣ Empaquetando nuestro microservicio para producción CÓMO CREAR UN MICROSERVICIO EN GO AGENDA: SPRINT 3
  26. CREAR UN CONSUMER CÓMO CREAR UN MICROSERVICIO EN GO dialer

    := kafka.Dial([]string{"http://localhost:9092"}) consumer := kafka.NewConsumer(dialer, "users", "users_group#1")
  27. CREANDO UN EVENT HANDLER CÓMO CREAR UN MICROSERVICIO EN GO

    go func() { if err := userConsumer.Read(rootCtx, userEventHandler.Handle); err != nil { cancel() log.Fatalln(err) } }() Read(ctx context.Context, handle Handler) error MÉTODO READ
  28. CREANDO UN EVENT HANDLER CÓMO CREAR UN MICROSERVICIO EN GO

    type Handler func(ctx context.Context, msg []byte) error
  29. CREANDO UN EVENT HANDLER CÓMO CREAR UN MICROSERVICIO EN GO

    type User struct { creatingService creating.Service } func NewUserHandler(creatingService creating.Service) *User { return &User{creatingService: creatingService} } type createdUserEventPayload struct { UserID string `mapstructure:"user_id"` UserName string `mapstructure:"user_name"` } func (u *User) Handle(ctx context.Context, message []byte) error { // code here return nil }
  30. PAQUETE DOMAIN CÓMO CREAR UN MICROSERVICIO EN GO type Event

    struct { ID string `json:"event_id"` EventType string `json:"event_type"` AggregateID string `json:"aggregate_id"` Payload interface{} `json:"payload"` OccurredOn time.Time `json:"occurred_on"` }
  31. PAQUETE DOMAIN CÓMO CREAR UN MICROSERVICIO EN GO func EventDecode(message

    []byte, payload interface{}) (Event, error) { var decoded Event err := json.Unmarshal(message, &decoded) if err != nil { return Event{}, nil } if err := decoded.decodePayload(payload); err != nil { return Event{}, nil } return decoded, nil } func (e *Event) decodePayload(i interface{}) error { return mapstructure.Decode(e.Payload, i) }
  32. CREAR UN PUBLISHER CÓMO CREAR UN MICROSERVICIO EN GO dialer

    := kafka.Dial([]string{"http://localhost:9092"}) kafkaCounterPublisher := kafka.NewPublisher(dialer, "counters")
  33. ABSTRAER NUESTRO PUBLISHER CÓMO CREAR UN MICROSERVICIO EN GO type

    publisher interface { Publish(ctx context.Context, payload interface{}) error } type Publisher struct { publisher publisher } func NewPublisher(p publisher) *Publisher { return &Publisher{publisher: p} } func (e *Publisher) Publish(ctx context.Context, events []domain.Event) error { for _, event := range events { if err := e.publisher.Publish(ctx, event); err != nil { return err } } return nil }
  34. ‣ Crear un contador por defecto cada vez que se

    recibe un mensaje de USER_CREATED ‣ Crear un nuevo endpoint: GET /counters/belongs-to/{user_id} ‣ Bonus: Publicar un mensaje en Kafka cada vez que un nuevo contador es creado. CÓMO CREAR UN MICROSERVICIO EN GO ¿QUÉ VAS A HACER EN ESTE SPRINT?