4. • Laufzeitumgebung sind Clouds und Cluster
• Komponenten sind Microservices
• Aufteilung bringt Flexibilität und Skalierbarkeit
• APIs auf Basis von REST oder gRPC bringen
Sprachunabhängigkeit
Runtime im Netz Frank Müller
6. • HTTP Bibliothek ist genug
• URL bezeichnet Typ und gegebenenfalls Ressource
• HTTP Methode bestimmt Aktion
• Create / Read / Update / Delete ist POST / GET / PUT / DELETE
• Body enthält die Daten
• Content Type ist in der Regel JSON
Einfache Struktur Frank Müller
8. • Package net/http enthält Server, Request und Response
• Es definiert den Handler und implementiert ihn als ServeMux
• Nicht hinreichend, aber leicht zu ergänzen
• Ein eigenes Package httpx hilft
‣ Pfade abbilden
‣ Methoden abbilden
Standardbibliothek genügt beinahe Frank Müller
9. // NestedHandler allows to nest handler following the
// pattern /handlerA/{entityID-A}/handlerB/{entityID-B}.
type NestedHandler struct {
resource string
handler http.Handler
nested map[string]http.Handler
}
func NewNestedHandler(resource string, handler http.Handler) *NestedHandler {
return &NestedHandler{
resource: resource,
handler: handler,
nested: make(map[string]http.Handler),
}
}
Pfade abbilden (1) Frank Müller
11. func (h *NestedHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Check if own or one of the nested handler is addressed.
eh, ok := h.analyzePath(r.URL.Path)
if ok {
eh.ServeHTTP(w, r)
return
}
// Handler not found.
http.NotFound(w, r)
}
Pfade abbilden (3) Frank Müller
12. // CreateHandler care for create requests, aka POST.
type CreateHandler interface {
Create(w http.ResponseWriter, r *http.Request)
}
// ReadHandler care for read requests, aka GET.
type ReadHandler interface {
Read(w http.ResponseWriter, r *http.Request)
}
.
.
.
Methoden abbilden (1) Frank Müller
13. // MethodHandler maps requests to according methods.
type MethodHandler struct {
handler http.Handler
}
// NewMethodHandler wraps a handler for automatic method mapping.
func NewMethodHandler(h http.Handler) *MethodHandler {
return &MethodHandler{
handler: h,
}
}
Methoden abbilden (2) Frank Müller
14. // ServeHTTP implements http.Handler and cares for the mapping.
func (h *MethodHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodPost:
if ch, ok := h.handler.(CreateHandler); ok {
ch.Create(w, r)
return
}
case http.MethodGet:
...
}
// Fallback.
h.handler.ServeHTTP(w, r)
}
Methoden abbilden (3) Frank Müller
16. • Handler jeweils für Logik von Shopping Cards und Items
• Wrapping durch MethodHandler
• Kombination durch NestedHandler
Beispiel Shopping API (1) Frank Müller
17. type CardsHandler struct { ... }
// Create to handle POST requests.
func (h *CardsHandler) Create(w http.ResponseWriter, r *http.Request) { ... }
// Read to handle GET requests.
func (h *CardsHandler) Read(w http.ResponseWriter, r *http.Request) { ... }
type ItemsHandler struct { ... }
// Create to handle POST requests.
func (h *ItemsHandler) Create(w http.ResponseWriter, r *http.Request) { ... }
// Read to handle GET requests.
func (h *ItemsHandler) Read(w http.ResponseWriter, r *http.Request) { ... }
Beispiel Shopping API (2) Frank Müller
18. // Little helper for convenience, wrapping with logging,
// authentication/authorization, and method handling.
wrap := func(h http.Handler) http.Handler {
return httpx.NewLogHandler(httpx.NewAuthHandler(httpx.NewMethodHandler(h)))
}
// Wrap the handlers for business logic.
ch := wrap(NewCardsHandler())
ih := wrap(NewItemsHandler())
// Nest the handlers for business logic of cards and their items.
ncih := httpx.NewNestedHandler("cards", ch).Nest("items", ih)
Beispiel Shopping API (3) Frank Müller
19. // Use standard multiplexer for all handlers.
mux := http.NewServeMux()
mux.Handle("/cards/", ncih)
// Configure and start server using the multiplexer.
s := &http.Server{
Addr: ":8080",
Handler: mux,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20,
}
log.Fatal(s.ListenAndServe())
Beispiel Shopping API (4) Frank Müller
20. • Analyse des Pfads an einer Position für Resource Identifier
• Analyse des Content Type
• Analyse weiterer Header
• Marshal und Unmarshal direkt in oder aus dem Body
Weitere Helfer für das Package Frank Müller
21. • Wenig Dependencies, wenig Komplexität, leichte Erweiterbarkeit
• Wrapping ist praktisch für modulare Erweiterung
‣ Authentisierung und Autorisierung
‣ Logging
• Testing der Geschäftslogik ist losgelöst von diesen Aspekten
Vorteile Frank Müller
22. • Eigenes Package erfordert Vorarbeit und eigene Wartung
• Marshalling und Unmarshalling der Transportobjekte bringt
manuelle Aufwände mit sich
Nachteile Frank Müller
24. •Remote Procedure Calls
•Bei Google entwickelt
•Nutzen in der Regel Protocol
Buffers
•Server bietet Dienste an
•Clients nutzen sie
Eigentlich nichts besonderes Frank Müller
Go Service
JS Client Java Client
gRPC
Server
gRPC
Stub
gRPC
Stub
Proto Request
Proto Request
Proto Response
Proto Responses
25. • Protocol Buffers beschreiben Datenstrukturen
‣ sprachunabhängig
‣ plattformunabhängig
‣ erweiterbar
• Serialisiert Daten für den Transport
•Stubs werden für Zielsprache und -plattform generiert
Grundlagen Frank Müller
26. • Definition in Proto-Datei
• Übertragung der Daten als Messages
• Verschiedene Felder stehen zur Verfügung
‣ Verschiedene Integers, String, Bool, Floats, Slice of Bytes
‣ Optionales, OneOf, Enumerations, Wiederholungen
‣ Default Value und Schachtelungen
Transport der Daten Frank Müller
27. // Message to add one item to an existing card.
message AddItemRequest {
required string card_id = 1;
required string article_no = 2;
optional group spec = 3 {
optional string size = 4;
optional string color = 5;
}
required uint64 number = 6;
}
// Message to reply to the adding of an article.
message AddItemReply { ... }
Nachrichten Frank Müller
28. // Service for the management of a shopping card.
service Cards {
// Create a new card.
rpc NewCard () returns (NewCardReply) {}
// Add an item.
rpc AddItem (AddItemRequest) returns (AddItemReply) {}
...
}
Services Frank Müller
29. Vorbereitung Frank Müller
## Installation der Plugins
$ go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.26
$ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1
## Pfad erweitern
$ export PATH="$PATH:$(go env GOPATH)/bin"
## gRPC Code generieren
$ protoc -I $SRCDIR --go_out $DSTDIR $SRCDIR/myshop.proto
30. // AddItem handels the AddItem call.
func (s *cardService) AddItem(
ctx context.Context, in *pb.AddItemRequest) (*pb.AddItemReply, error) {
// Use data of AddItemRequest in to add the item, e.g.
card, err := s.loadCard(in.CardId)
if err != nil {
return nil, err
}
...
// Return the reply.
return &pb.AddItemReply{
...
}, nil
}
Server (1) Frank Müller
31. // Start listener and GRPC server.
lis, err := net.Listen("tcp", ":10000")
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
grpcServer := grpc.NewServer()
// Register card service.
myshop.RegisterCardServer(grpcServer, &cardService{})
// Start serving.
grpcServer.Serve(lis)
Server (2) Frank Müller
32. // Connect the server.
conn, err := grpc.Dial("localhost:10000")
if err != nil {
log.Fatalf("failed to connect the server: %v", err)
}
defer conn.Close()
// Start the client.
client := calculator.NewCardClient(conn)
// Perform requests using the created client.
reply, err := client.AddItem(context.Background(), &pb.AddItemRequest{ ... })
...
Client Frank Müller
33. • Statische Datenformate
• Effiziente Serialisierung
• Streaming möglich
• Connections können beibehalten werden
• Umfangreicher Stack für Security und Credentials
• Problemloser Mix verschiedener Sprachen
Vorteile Frank Müller
34. • Nicht für alle Sprachen verfügbar
• Proto-Dateien sind eigene Artefakte (bei Mehrsprachigkeit eher
Vorteil)
• Extra Tools notwendig
Nachteile Frank Müller
36. • RESTful APIs sind etabliert und flexibel
• Sie können in vielen Sprachen leicht implementiert werden
• Unabhängigkeit von Sprachen und Plattformen
• gRPC ist ein leistungsstarker Nachfolger
• Definition in Proto-Dateien erlaubt leichteren Austausch
• Generator nicht für alle Sprachen verfügbar
Zusammenfassung Frank Müller