Mit CQRS findet eine Architektur immer mehr Anklang, die sich von einer klassischen CRUD-Abbildung von Fachlichkeiten löst. Statt verschiedene Entitäten zu ändern, um beispielsweise einen Buchungsvorgang umzusetzen, wird ein Command verwendet, der alle notwendigen Informationen bündelt und die Aufgabe fachlich abbildet. Wie lassen sich solche Commands jedoch in einem API abbilden? REST konzentriert sich auf Entitäten und bildet CRUD für diese Entitäten ab. Wie bildet man jedoch Commands in einem API ab? Genau hier ist GraphQL hervorragend geeignet. In dieser Session betrachten wir, wie GraphQL für eine fachlich getriebene Interaktion verwendet werden kann und dadurch mit CQRS harmoniert. An konkreten Beispielen wird ersichtlich, wo die Stärken von GraphQL gegenüber einem REST API für CQRS liegen.
Im Kontext von APIs kommt derzeit keiner an REST (Representational State Transfer) vorbei. REST gilt als leichtgewichtige, skalierbare und schnell erlernbare Alternative zu SOAP, die sich die vorhandene Infrastruktur des WWW zunutze macht. In der Praxis hat aber auch REST seine Schwächen. So ist gutes API-Design häufig eine Herausforderung. Für mobile Anwendungen ist REST zu starr und geht nicht effizient genug mit Bandbreite um.
Im Vortrag werden Stärken und Schwächen von REST aufgezeigt und mit GraphQL eine Alternative speziell für den mobilen Kontext vorgestellt.
REST APIs liegen im Trend und werden daher in vielen Projekten eingesetzt. REST besitzt Schwächen, die bei falschem Einsatz schnell sichtbar werden. Dieser Vortrag zeigt die Probleme und Schächen von REST und beschreibt die Alternativen: GraphQL, JSON Path und GRPC.
Folien zu unserem Vortrag beim Java Forum Stuttgart 2014
Besuchen Sie uns unter http://www.thecodecampus.de
Müssen Sie auch noch alte servergetriebene Java-Webanwendungen weiterentwickeln und wollen Ihre Kunden dabei den Genuss der Usability moderner Webseiten bieten?
In unserem Talk beim JavaForum Stuttgart 2014 haben wir anhand von Codebeispielen und Erfahrungsberichten gezeigt wie man schrittweise AngularJS in bestehende Anwendungen integriert. Dieser agile Ansatz liefert schnelle Ergebnisse und reduziert die Kosten und Risiken im Vergleich zu einer kompletten Umstellung.
17 years after Fieldings paper REST is at its peak. Every interface has to use REST. But there are many problems in using and designing REST APIs. This sessions describes the problems and encourages to use besides REST other means of communication.
Web-APIs sind das aktuelle Trend-Thema in den IT-Abteilungen. Als primärer Kommunikationspartner für Fat, Mobil und Web-Clients sind Web-APIs das Rückgrat moderner verteilter Anwendungen. Sind synchrone Requests via REST und GraphQL oder Push-Notifications via Server-Sent Events und WebSocket die bessere Wahl? Welches Austauschformat sollte man wählen? Wie sieht gutes „Error Handling“ aus? Und was ist mit Themen wie Security und Versionierung? Lebensnahe Beispiele, jede Menge Best-Practices und viel Code, der nahtlos in eigene Projekte übernommen werden kann, bilden die Grundlage für die Session.
Im Kontext von APIs kommt derzeit keiner an REST (Representational State Transfer) vorbei. REST gilt als leichtgewichtige, skalierbare und schnell erlernbare Alternative zu SOAP, die sich die vorhandene Infrastruktur des WWW zunutze macht. In der Praxis hat aber auch REST seine Schwächen. So ist gutes API-Design häufig eine Herausforderung. Für mobile Anwendungen ist REST zu starr und geht nicht effizient genug mit Bandbreite um.
Im Vortrag werden Stärken und Schwächen von REST aufgezeigt und mit GraphQL eine Alternative speziell für den mobilen Kontext vorgestellt.
REST APIs liegen im Trend und werden daher in vielen Projekten eingesetzt. REST besitzt Schwächen, die bei falschem Einsatz schnell sichtbar werden. Dieser Vortrag zeigt die Probleme und Schächen von REST und beschreibt die Alternativen: GraphQL, JSON Path und GRPC.
Folien zu unserem Vortrag beim Java Forum Stuttgart 2014
Besuchen Sie uns unter http://www.thecodecampus.de
Müssen Sie auch noch alte servergetriebene Java-Webanwendungen weiterentwickeln und wollen Ihre Kunden dabei den Genuss der Usability moderner Webseiten bieten?
In unserem Talk beim JavaForum Stuttgart 2014 haben wir anhand von Codebeispielen und Erfahrungsberichten gezeigt wie man schrittweise AngularJS in bestehende Anwendungen integriert. Dieser agile Ansatz liefert schnelle Ergebnisse und reduziert die Kosten und Risiken im Vergleich zu einer kompletten Umstellung.
17 years after Fieldings paper REST is at its peak. Every interface has to use REST. But there are many problems in using and designing REST APIs. This sessions describes the problems and encourages to use besides REST other means of communication.
Web-APIs sind das aktuelle Trend-Thema in den IT-Abteilungen. Als primärer Kommunikationspartner für Fat, Mobil und Web-Clients sind Web-APIs das Rückgrat moderner verteilter Anwendungen. Sind synchrone Requests via REST und GraphQL oder Push-Notifications via Server-Sent Events und WebSocket die bessere Wahl? Welches Austauschformat sollte man wählen? Wie sieht gutes „Error Handling“ aus? Und was ist mit Themen wie Security und Versionierung? Lebensnahe Beispiele, jede Menge Best-Practices und viel Code, der nahtlos in eigene Projekte übernommen werden kann, bilden die Grundlage für die Session.
Data Scraping with Excel - Campixx 2013 - Maik SchmidtMaik Schmidt
Auf meiner Campixx Session habe ich gezeigt, wie man mit Hilfe von Excel und X-Path Daten aus dem Web scrapen kann. u.a. wurden gescraped: Standard KPIs, Malware Checker, Index Checker, Google SERPs, Google Suggest
Presentation at the OGD2011 conference taking place in Vienna on the 16th of June 2011 as well as at the LOD2 CKAn workshop on 15th of June 2011: CKAN by Friedrich Lindenberg, Open Knowledge Foundation.
(License: CC-BY 3.0)
Im #Neuland gibt es noch heute stark in die Jahre gekommene Host- und Service-Monitoring-Lösungen, die zu den unliebsamen Langzeitbaustellen vieler Teams und Unternehmen gehören. Wer kennt es nicht, dass regelmäßige „False-Positive“-Alarme sich in Form von E-Mails oder SMS lästig bekannt machen, dass Webinterfaces schnell an ihre Grenzen stoßen, dass komplexe und benutzerfreundliche Graphen generiert werden sollen oder dass das Monitoring-Konstrukt nicht mit der großen Zahl an hippen neuen Docker-basierten Services/Checks zurechtkommt. Ganz zu schweigen von den lückenhaften oder fehlenden Programmierschnittstellen vieler Monitoring-Monolithen. In diesem Vortrag möchten wir euch eine auf Prometheus und Kubernetes basierende Musterlösung vorstellen, die eine Webapplikation über verschiedene Metriken hinweg überwacht und das DevOps-Betriebsteam zum richtigen Zeitpunkt auf konkrete Probleme aufmerksam macht.
Event: DevOpsCon, 06.12.2016
Speaker: Christoph Petrausch, inovex GmbH
Mehr Tech-Vorträge: https://www.inovex.de/de/content-pool/vortraege/
RVK 3.0 - Die Regensburger Verbundklassifikation als Normdatei für Bibliothek...Magnus Pfeffer
Projektbereicht auf dem RVK Anwendertreffen am 18. Oktober 2011 in Regensburg.
Kurzer Überblick über die Anforderungen an Normdaten und Ontologien im Semantic Web und wie die RVK "auf Stand" gebracht werden kann.
Nach einer kurzen Einführung in verteilte Systeme zeige ich die Motivation für die Entstehung von NoSQL-Datenbanken auf. Ich stelle die Haupt-Kategorien der NoSQL-Datenbanken vor: Key-Value, Column Store, Graphen- und Dokumentenoriente Datenbanken. Danach gehe ich auf konkrete Datenbanken wie MongoDB, Neo4j und Redis ein.
This presentation was held on the DOAG 2018 conference in Nuremberg. It describes how to handle REST Webservice with Web Source Moduls inside APEX 18. Examples like using fantasydata and jira as webservices endpoints are described.
Cloud Observability mit Loki, Prometheus, Tempo und GrafanaQAware GmbH
Mastering Kubernetes, Juli 2022, Franz Wimmer (@zalintyre, Senior Software Engineer bei QAware).
== Dokument bitte herunterladen, falls unscharf! Please download slides if blurred! ==
Cloud Observability mit Loki, Prometheus, Tempo und Grafana
Observability ist eine entscheidende Komponente jeder ernsthaften Kubernetes-basierten Plattform. Nur so können der zuverlässige Betrieb Cloud-nativer Anwendungen und das schnelle Debugging kniffligster Probleme, die nur in der Produktionsumgebung auftreten, durch die Entwickler gewährleistet werden.
Die wesentlichen Säulen guter Observability sind Logs, Metriken und Traces. Es gibt eine große Anzahl kommerzieller Tools und SaaS-Anbieterr, welche die Aggregation und Analyse der relevanten Diagnosedaten unterstützen.
In diesem Vortrag verwenden wir hingegen einen vollständig auf Open-Source-Bausteinen basierenden Stack: Promtail zum Weiterleiten von Logs an Loki, Prometheus zum Sammeln von Metriken und Tempo zum Empfangen von Traces. Wir zeigen zudem, wie mit der neuen Exemplars-Storage-Funktion der schnelle Übergang von Metriken zu Traces und Logs möglich wird.
Rufen Sie nicht an – wir rufen Sie an! | Server-sent Events und Web-Sockets i...OPEN KNOWLEDGE GmbH
Speaker: Sebastian Reiners
Seit Java EE 7 stehen auch Enterprise-Entwicklern Server-Sent Events und WebSockets in standardisierter Form zur Verfügung. Höchste Zeit also, sich diese andere Art der Kommunikation im Web einmal näher anzusehen. Was sind Server-Sent Events und WebSockets überhaupt, was sind ihre Vorteile und wo bieten sich sinnvolle Anwendungsbereiche?
Im Rahmen der Vorstellung der unterschiedlichen Ansätze werden praktische Erfahrungen und Fallstricke, insbesondere im Zusammenspiel mit JSF und CDI veranschaulicht, sowie ein erstes Resümee gezogen.
Data Scraping with Excel - Campixx 2013 - Maik SchmidtMaik Schmidt
Auf meiner Campixx Session habe ich gezeigt, wie man mit Hilfe von Excel und X-Path Daten aus dem Web scrapen kann. u.a. wurden gescraped: Standard KPIs, Malware Checker, Index Checker, Google SERPs, Google Suggest
Presentation at the OGD2011 conference taking place in Vienna on the 16th of June 2011 as well as at the LOD2 CKAn workshop on 15th of June 2011: CKAN by Friedrich Lindenberg, Open Knowledge Foundation.
(License: CC-BY 3.0)
Im #Neuland gibt es noch heute stark in die Jahre gekommene Host- und Service-Monitoring-Lösungen, die zu den unliebsamen Langzeitbaustellen vieler Teams und Unternehmen gehören. Wer kennt es nicht, dass regelmäßige „False-Positive“-Alarme sich in Form von E-Mails oder SMS lästig bekannt machen, dass Webinterfaces schnell an ihre Grenzen stoßen, dass komplexe und benutzerfreundliche Graphen generiert werden sollen oder dass das Monitoring-Konstrukt nicht mit der großen Zahl an hippen neuen Docker-basierten Services/Checks zurechtkommt. Ganz zu schweigen von den lückenhaften oder fehlenden Programmierschnittstellen vieler Monitoring-Monolithen. In diesem Vortrag möchten wir euch eine auf Prometheus und Kubernetes basierende Musterlösung vorstellen, die eine Webapplikation über verschiedene Metriken hinweg überwacht und das DevOps-Betriebsteam zum richtigen Zeitpunkt auf konkrete Probleme aufmerksam macht.
Event: DevOpsCon, 06.12.2016
Speaker: Christoph Petrausch, inovex GmbH
Mehr Tech-Vorträge: https://www.inovex.de/de/content-pool/vortraege/
RVK 3.0 - Die Regensburger Verbundklassifikation als Normdatei für Bibliothek...Magnus Pfeffer
Projektbereicht auf dem RVK Anwendertreffen am 18. Oktober 2011 in Regensburg.
Kurzer Überblick über die Anforderungen an Normdaten und Ontologien im Semantic Web und wie die RVK "auf Stand" gebracht werden kann.
Nach einer kurzen Einführung in verteilte Systeme zeige ich die Motivation für die Entstehung von NoSQL-Datenbanken auf. Ich stelle die Haupt-Kategorien der NoSQL-Datenbanken vor: Key-Value, Column Store, Graphen- und Dokumentenoriente Datenbanken. Danach gehe ich auf konkrete Datenbanken wie MongoDB, Neo4j und Redis ein.
This presentation was held on the DOAG 2018 conference in Nuremberg. It describes how to handle REST Webservice with Web Source Moduls inside APEX 18. Examples like using fantasydata and jira as webservices endpoints are described.
Cloud Observability mit Loki, Prometheus, Tempo und GrafanaQAware GmbH
Mastering Kubernetes, Juli 2022, Franz Wimmer (@zalintyre, Senior Software Engineer bei QAware).
== Dokument bitte herunterladen, falls unscharf! Please download slides if blurred! ==
Cloud Observability mit Loki, Prometheus, Tempo und Grafana
Observability ist eine entscheidende Komponente jeder ernsthaften Kubernetes-basierten Plattform. Nur so können der zuverlässige Betrieb Cloud-nativer Anwendungen und das schnelle Debugging kniffligster Probleme, die nur in der Produktionsumgebung auftreten, durch die Entwickler gewährleistet werden.
Die wesentlichen Säulen guter Observability sind Logs, Metriken und Traces. Es gibt eine große Anzahl kommerzieller Tools und SaaS-Anbieterr, welche die Aggregation und Analyse der relevanten Diagnosedaten unterstützen.
In diesem Vortrag verwenden wir hingegen einen vollständig auf Open-Source-Bausteinen basierenden Stack: Promtail zum Weiterleiten von Logs an Loki, Prometheus zum Sammeln von Metriken und Tempo zum Empfangen von Traces. Wir zeigen zudem, wie mit der neuen Exemplars-Storage-Funktion der schnelle Übergang von Metriken zu Traces und Logs möglich wird.
Rufen Sie nicht an – wir rufen Sie an! | Server-sent Events und Web-Sockets i...OPEN KNOWLEDGE GmbH
Speaker: Sebastian Reiners
Seit Java EE 7 stehen auch Enterprise-Entwicklern Server-Sent Events und WebSockets in standardisierter Form zur Verfügung. Höchste Zeit also, sich diese andere Art der Kommunikation im Web einmal näher anzusehen. Was sind Server-Sent Events und WebSockets überhaupt, was sind ihre Vorteile und wo bieten sich sinnvolle Anwendungsbereiche?
Im Rahmen der Vorstellung der unterschiedlichen Ansätze werden praktische Erfahrungen und Fallstricke, insbesondere im Zusammenspiel mit JSF und CDI veranschaulicht, sowie ein erstes Resümee gezogen.
3. 3
Was ist denn eigentlich REST?
• Alle relevanten Daten sind über eine URI erreichbar
http://smart.service/api/resources/<resource-id>
• Änderungen an den Daten werden mittels HTTP Requests und
passenden Verben durchgeführt
POST http://smart.service/api/resources/
GET http://smart.service/api/resources/<resource-id>
DELETE http://smart.service/api/resources/<resource-id>
4. 3
Was ist denn eigentlich REST?
• Alle relevanten Daten sind über eine URI erreichbar
http://smart.service/api/resources/<resource-id>
• Änderungen an den Daten werden mittels HTTP Requests und
passenden Verben durchgeführt
POST http://smart.service/api/resources/
GET http://smart.service/api/resources/<resource-id>
DELETE http://smart.service/api/resources/<resource-id>
Kein REST ist:
GET http://dumb.service/api/resources/<id>/applyColorBlue
15. 8
Guthaben erhöhen
• Ausstellen neuer Karten
• Guthaben einlösen
• Guthaben erhöhen
• Karte stornieren
• Einlösung stornieren
PUT http://svc.local/api/giftcards/102
Accept: application/json
Content-Type: application/json
{
"amount": 80
}
Request HTTP/1.1 201 CREATED
Content-Type: application/json
{
"id": 102,
"amount": 80
}
Response
Ist das der Betrag um
den das Guthaben
erhöht werden soll?
Oder ist es der neue
Zielbetrag?
16. 9
Karte stornieren
• Ausstellen neuer Karten
• Guthaben einlösen
• Guthaben erhöhen
• Karte stornieren
• Einlösung stornieren
Was ist eigentlich eine Stornierung?
• Löschung mittels DELETE?
Der Datensatz sollte weiterhin existieren für
eine Nachverfolgung
• Eine Aktualisierung mittels PUT?
Das steht in Konkurrenz zu Erhöhung des
Guthabens
20. 13
Einlösung stornieren
• Ausstellen neuer Karten
• Guthaben einlösen
• Guthaben erhöhen
• Karte stornieren
• Einlösung stornieren
DELETE http://svc.local/api/giftcards/102/transactions/203
• Der Datensatz soll nicht gelöscht werden
• Auch wird der Datensatz selbst nicht geändert, sondern ein
neuer angelegt
21. 14
Einlösung stornieren
• Ausstellen neuer Karten
• Guthaben einlösen
• Guthaben erhöhen
• Karte stornieren
• Einlösung stornieren
POST http://svc.local/api/giftcards/102/transactions
• Der Body des POST könnte ein Flag tragen, das den Datensatz
als Stornierung kennzeichnet
• Steht in Konkurrenz zu normalen Transaktionen
POST http://svc.local/api/giftcards/102/transactions
Accept: application/json
Content-Type: application/json
{
"amount": -11,
„revokedTransactionId": 203
}
Request
23. 16
GraphQL Schnelleinstieg
• GraphQL ist ein Mechanismus für die Kommunikation
zwischen Client und Server
• Die technische Übertragung ist typischerweise HTTP
• Kern von GraphQL ist das GraphQL Schema
• Das GraphQL Schema definiert, welche Daten der Server
bereitstellen kann
24. 17
GraphQL Schnelleinstieg: Das Schema
• Das GraphQL Schema basiert auf
Typen
type Type {
field: StrictType
}
type StrictType {
valueNeverNull: String!
}
type PrimitiveFields {
identifier: ID!
numeric: Int!
}
type TypeWithArrays {
strings: [String]
strictList: [StrictType!]!
}
25. 18
GraphQL Schnelleinstieg: Das Schema
• Das GraphQL Schema basiert auf
Typen
• Ein Typ besteht aus Feldern und
deren Typisierung
type Type {
field: StrictType
}
type StrictType {
valueNeverNull: String!
}
type PrimitiveFields {
identifier: ID!
numeric: Int!
}
type TypeWithArrays {
strings: [String]
strictList: [StrictType!]!
}
26. 19
GraphQL Schnelleinstieg: Das Schema
• Das GraphQL Schema basiert auf
Typen
• Ein Typ besteht aus Feldern und
deren Typisierung
• Felder können explizit als non-
nullable deklariert werden
type Type {
field: StrictType
}
type StrictType {
valueNeverNull: String!
}
type PrimitiveFields {
identifier: ID!
numeric: Int!
}
type TypeWithArrays {
strings: [String]
strictList: [StrictType!]!
}
27. 20
GraphQL Schnelleinstieg: Das Schema
• Das GraphQL Schema basiert auf
Typen
• Ein Typ besteht aus Feldern und
deren Typisierung
• Felder können explizit als non-
nullable deklariert werden
• Die Typen der Felder sind entweder
deklarierte Typen oder Scalars
type Type {
field: StrictType
}
type StrictType {
valueNeverNull: String!
}
type PrimitiveFields {
identifier: ID!
numeric: Int!
}
type TypeWithArrays {
strings: [String]
strictList: [StrictType!]!
}
28. 21
GraphQL Schnelleinstieg: Das Schema
• Das GraphQL Schema basiert auf
Typen
• Ein Typ besteht aus Feldern und
deren Typisierung
• Felder können explizit als non-
nullable deklariert werden
• Die Typen der Felder sind entweder
deklarierte Typen oder Scalars
• Listen werden ebenfalls typisiert
definiert
type Type {
field: StrictType
}
type StrictType {
valueNeverNull: String!
}
type PrimitiveFields {
identifier: ID!
numeric: Int!
}
type TypeWithArrays {
strings: [String]
strictList: [StrictType!]!
}
29. 22
GraphQL Schnelleinstieg: Das Schema
• Felder können Argumente erhalten
• Anhand der Argumente kann der
Zugriff auf das Feld konfiguriert
werden
type Type {
field(filter: String!): ResultType
other(filter: Filter!): ResultType
}
input Filter {
text: String
maxResults: Int
}
30. 23
GraphQL Schnelleinstieg: Das Schema
• Felder können Argumente erhalten
• Anhand der Argumente kann der
Zugriff auf das Feld konfiguriert
werden
• Komplexere Argumente können in
eigenen Input-Typen definiert
werden
type Type {
field(filter: String!): ResultType
other(filter: Filter!): ResultType
}
input Filter {
text: String
maxResults: Int
}
31. 24
GraphQL Schnelleinstieg: Das Schema
Das GraphQL Schema bietet noch weitere Möglichkeiten
• Union Types
• Enum
• Eigene Skalare
• Interfaces
33. 26
GraphQL Schnelleinstieg: Das Schema
Das Schema definiert drei
Einstiegspunkte in den Graphen:
• Query
type Query {
#...
}
34. 27
GraphQL Schnelleinstieg: Das Schema
Das Schema definiert drei
Einstiegspunkte in den Graphen:
• Query
• Mutation
type Query {
#...
}
type Mutation {
#...
}
35. 28
GraphQL Schnelleinstieg: Das Schema
Das Schema definiert drei
Einstiegspunkte in den Graphen:
• Query
• Mutation
• Subscription
type Query {
#...
}
type Mutation {
#...
}
type Subscription {
#...
}
36. 29
GraphQL Schnelleinstieg: Das Schema
• Query ist der Einstieg in den
Graphen
• Daten die für den Client abrufbar
sein sollen, müssen direkt oder
indirekt über Query erreichbar sein
• Die Komplexität des Graphen ist
wenig limitiert
type Query {
companies: [Company!]!
company(id: ID!): Company
}
type Company {
id: ID!
name: String!
locations: [Location!]!
}
type Location {
name: String!
address: Address
}
type Address {
addressLines: [String!]!
city: String!
postalCode: String!
Country: String!
}
39. 32
GraphQL Schnelleinstieg: Queries
Eine Query definiert, welche Daten aus dem Grafen
ausgelesen werden sollen
type Query {
companies: [Company!]!
company(id: ID!): Company
}
type Company {
id: ID!
name: String!
locations: [Location!]!
}
type Location {
name: String!
address: Address
}
type Address {
addressLines: [String!]!
city: String!
postalCode: String!
Country: String!
}
40. 32
GraphQL Schnelleinstieg: Queries
Eine Query definiert, welche Daten aus dem Grafen
ausgelesen werden sollen
type Query {
companies: [Company!]!
company(id: ID!): Company
}
type Company {
id: ID!
name: String!
locations: [Location!]!
}
type Location {
name: String!
address: Address
}
type Address {
addressLines: [String!]!
city: String!
postalCode: String!
Country: String!
}
query {
companies {
name
locations {
name
}
}
}
41. 32
GraphQL Schnelleinstieg: Queries
Eine Query definiert, welche Daten aus dem Grafen
ausgelesen werden sollen
type Query {
companies: [Company!]!
company(id: ID!): Company
}
type Company {
id: ID!
name: String!
locations: [Location!]!
}
type Location {
name: String!
address: Address
}
type Address {
addressLines: [String!]!
city: String!
postalCode: String!
Country: String!
}
query {
companies {
name
locations {
name
}
}
}
{
"data": {
"companies": [
{
"name": "Apple",
"locations": [
{
"name": "Campus"
}
]
}
]
}
}
42. 32
GraphQL Schnelleinstieg: Queries
Eine Query definiert, welche Daten aus dem Grafen
ausgelesen werden sollen
type Query {
companies: [Company!]!
company(id: ID!): Company
}
type Company {
id: ID!
name: String!
locations: [Location!]!
}
type Location {
name: String!
address: Address
}
type Address {
addressLines: [String!]!
city: String!
postalCode: String!
Country: String!
}
query {
companies {
name
locations {
name
}
}
}
{
"data": {
"companies": [
{
"name": "Apple",
"locations": [
{
"name": "Campus"
}
]
}
]
}
}
Ein GraphQL Server antwortet nur mit den
Daten, die explizit angefordert wurden
64. 45
Klassische Architekturen
• Es gibt ein zentrales Daten-Modell
• Der Zugriff auf alle relevanten Daten der
Applikation erfolgt über das Daten-Modell
• Das Daten-Modell wird sowohl für
schreibende als auch lesende Zugriffe
verwendet
• Damit verbunden muss dieses Datenmodell
auch alle Use Cases abbilden können
Data Model
Data
Store
W
r
i
t
e
R
e
a
d
65. 46
Command & Query Responsibility Separation
Write
Data Model
Data
Store
Write
(Comma
nd)
66. 46
Command & Query Responsibility Separation
• Mit CQRS, sind schreibende (commands)
und lesende (queries) Zugriffe getrennt
• Commands definieren, welche Änderung
durchgeführt werden sollen
• Die zugehörige Command Handler
implementiert die fachliche Logik
Write
Data Model
Data
Store
Write
(Comma
nd)
67. 46
Command & Query Responsibility Separation
• Mit CQRS, sind schreibende (commands)
und lesende (queries) Zugriffe getrennt
• Commands definieren, welche Änderung
durchgeführt werden sollen
• Die zugehörige Command Handler
implementiert die fachliche Logik
• War ein Command erfolgreich, wird aus
dem neuen Zustand ein Read Model
abgeleitet (Projection)
Write
Data Model
Data
Store
Write
(Comma
nd)
Read
Data Model
Data
Store
Read
(Query
Projection
68. 47
Read Model Projections
• Es gibt keine zwingende 1:1
Beziehung zwischen Write und Read
Model
• Es können beliebig viele Read
Models existieren
• Ein Read Model kann für einen
spezifischen Einsatzzweck optimiert
werden
Read
Data Model Y
Data
Store
Read
(Query
Read
Data Model X
Data
Store
Read
(Query
Projection
70. 49
Sequenz der Events
• Beim Event Sourcing wird der Zustand der Daten in
Form einer Sequenz von Events abgebildet
• Diese Events werden nicht geändert
• Änderungen erfolgen durch das Hinzufügen neuer
Events
71. 49
Sequenz der Events
• Beim Event Sourcing wird der Zustand der Daten in
Form einer Sequenz von Events abgebildet
• Diese Events werden nicht geändert
• Änderungen erfolgen durch das Hinzufügen neuer
Events
{
"FirstName": "Maria",
"LastName": "Strong"
}
CreateContactEvent
72. 49
Sequenz der Events
• Beim Event Sourcing wird der Zustand der Daten in
Form einer Sequenz von Events abgebildet
• Diese Events werden nicht geändert
• Änderungen erfolgen durch das Hinzufügen neuer
Events
{
"FirstName": "Maria",
"LastName": "Strong"
}
CreateContactEvent
{
"LastName": "Fisher"
}
NameChangedEvent
73. 49
Sequenz der Events
• Beim Event Sourcing wird der Zustand der Daten in
Form einer Sequenz von Events abgebildet
• Diese Events werden nicht geändert
• Änderungen erfolgen durch das Hinzufügen neuer
Events
{
"FirstName": "Maria",
"LastName": "Strong"
}
CreateContactEvent
{
"LastName": "Fisher"
}
NameChangedEvent
{
"email": "m.f@aol.com"
}
EMailAddressChangedEvent
76. 51
Command Handling mit Events
Write Model
Command
Handling
Logic
Event
Store
1
1. Schreiboperation wird
gestartet (Command)
77. 51
Command Handling mit Events
Write Model
Command
Handling
Logic
Event
Store
1
2
1. Schreiboperation wird
gestartet (Command)
2. Der Zustand des Write Model
wird aus der Sequenz der
Events wiederhergestellt
(sourced)
78. 51
Command Handling mit Events
Write Model
Command
Handling
Logic
Event
Store
1
2
3
1. Schreiboperation wird
gestartet (Command)
2. Der Zustand des Write Model
wird aus der Sequenz der
Events wiederhergestellt
(sourced)
3. Die Command Handling
Logic vergleicht das
Command mit dem Write
Model und führt
79. 51
Command Handling mit Events
Write Model
Command
Handling
Logic
Event
Store
1
2
3
4
1. Schreiboperation wird
gestartet (Command)
2. Der Zustand des Write Model
wird aus der Sequenz der
Events wiederhergestellt
(sourced)
3. Die Command Handling
Logic vergleicht das
Command mit dem Write
Model und führt
4. Änderungen werden als
Events abgebildet und in
einem Event Store
gespeichert
81. 52
Mehr Möglichkeiten mit Projections
Write Model
Command
Handling
Logic
Event
Store
1
1. Events werden, wie
bereits beschrieben, im
Event Store gespeichert
82. 52
Mehr Möglichkeiten mit Projections
Write Model
Command
Handling
Logic
Event
Store
2
1
1. Events werden, wie
bereits beschrieben, im
Event Store gespeichert
2. Bei der erfolgreichen
Persistierung, wird der
Event auch über einen
Event Bus verteilt
Event Bus
83. 52
Mehr Möglichkeiten mit Projections
Write Model
Command
Handling
Logic
Event
Store
2
3
1
1. Events werden, wie
bereits beschrieben, im
Event Store gespeichert
2. Bei der erfolgreichen
Persistierung, wird der
Event auch über einen
Event Bus verteilt
3. Basierend auf diesen
Events, können viele
verschiedene
Projektionen erstellt oder
auch andere Integration
geschaffen werden
Event Bus
Read Model X Read Model Y Read Model Z
eMail
Notification
Analytics
101. 58
@Controller
class MutationController(
private val gateway: CommandGateway
) {
@MutationMapping
fun issueCard(@Argument amount: Int): IssueCardResult {
val id = UUID.randomUUID().toString()
gateway.sendAndWait<Unit>(
IssueCardCommand(
id = id,
amount = amount
)
)
return IssueCardResult(id, amount)
}
}
type Mutation {
issueCard(amount: Int!): IssueCardResult
# ...
}
102. 59
@Controller
class MutationController(
private val gateway: CommandGateway
) {
@MutationMapping
fun issueCard(@Argument amount: Int): IssueCardResult {
val id = UUID.randomUUID().toString()
gateway.sendAndWait<Unit>(
IssueCardCommand(
id = id,
amount = amount
)
)
return IssueCardResult(id, amount)
}
}
type Mutation {
issueCard(amount: Int!): IssueCardResult
# ...
} • Die Spring Boot Integration
für GraphQL basiert auf
dem Controller-Konzept
103. 60
@Controller
class MutationController(
private val gateway: CommandGateway
) {
@MutationMapping
fun issueCard(@Argument amount: Int): IssueCardResult {
val id = UUID.randomUUID().toString()
gateway.sendAndWait<Unit>(
IssueCardCommand(
id = id,
amount = amount
)
)
return IssueCardResult(id, amount)
}
}
type Mutation {
issueCard(amount: Int!): IssueCardResult
# ...
} • Die Spring Boot Integration
für GraphQL basiert auf
dem Controller-Konzept
104. 61
@Controller
class MutationController(
private val gateway: CommandGateway
) {
@MutationMapping
fun issueCard(@Argument amount: Int): IssueCardResult {
val id = UUID.randomUUID().toString()
gateway.sendAndWait<Unit>(
IssueCardCommand(
id = id,
amount = amount
)
)
return IssueCardResult(id, amount)
}
}
type Mutation {
issueCard(amount: Int!): IssueCardResult
# ...
} • Die Spring Boot Integration
für GraphQL basiert auf
dem Controller-Konzept
• GraphQL-Spezifische
Mapping-Annotationen
definieren die Handler
105. 62
@Controller
class MutationController(
private val gateway: CommandGateway
) {
@MutationMapping
fun issueCard(@Argument amount: Int): IssueCardResult {
val id = UUID.randomUUID().toString()
gateway.sendAndWait<Unit>(
IssueCardCommand(
id = id,
amount = amount
)
)
return IssueCardResult(id, amount)
}
}
type Mutation {
issueCard(amount: Int!): IssueCardResult
# ...
} • Die Spring Boot Integration
für GraphQL basiert auf
dem Controller-Konzept
• GraphQL-Spezifische
Mapping-Annotationen
definieren die Handler
• Zentrales Element sind die
Commands
106. 63
@Controller
class MutationController(
private val gateway: CommandGateway
) {
@MutationMapping
fun issueCard(@Argument amount: Int): IssueCardResult {
val id = UUID.randomUUID().toString()
gateway.sendAndWait<Unit>(
IssueCardCommand(
id = id,
amount = amount
)
)
return IssueCardResult(id, amount)
}
}
type Mutation {
issueCard(amount: Int!): IssueCardResult
# ...
} • Die Spring Boot Integration
für GraphQL basiert auf
dem Controller-Konzept
• GraphQL-Spezifische
Mapping-Annotationen
definieren die Handler
• Zentrales Element sind die
Commands
• Commands werden über
den CommandGateway
verschickt
107. 64
@Controller
class MutationController(
private val gateway: CommandGateway
) {
@MutationMapping
fun issueCard(@Argument amount: Int): IssueCardResult {
val id = UUID.randomUUID().toString()
gateway.sendAndWait<Unit>(
IssueCardCommand(
id = id,
amount = amount
)
)
return IssueCardResult(id, amount)
}
}
type Mutation {
issueCard(amount: Int!): IssueCardResult
# ...
} • Die Spring Boot Integration
für GraphQL basiert auf
dem Controller-Konzept
• GraphQL-Spezifische
Mapping-Annotationen
definieren die Handler
• Zentrales Element sind die
Commands
• Commands werden über
den CommandGateway
verschickt
108. 65
@MutationMapping
fun redeemCard(
@Argument cardId: String,
@Argument amount: Int): RedeemCardResult {
val transaction =
gateway.sendAndWait<GiftCardTransaction>(
RedeemCardCommand(
id = cardId,
amount = amount
)
)
return RedeemCardResult(transaction.remainingAmount)
}
type Mutation {
redeemCard(cardId: ID!, amount: Int!): RedeemCardResult
# ...
}
110. 67
var amount by Delegates.notNull<Int>()
var revoked = false
@CommandHandler
fun handle(cmd: RedeemCardCommand): GiftCardTransaction {
if (revoked)
throw IllegalStateException("card has been revoked")
if (cmd.amount <= 0)
throw IllegalArgumentException(
"invalid amount ${cmd.amount}")
if (cmd.amount > amount)
throw IllegalArgumentException(
„insufficient card credit")
val transactionId = newTransactionId()
val e = RedeemedEvent(
id = id,
transactionId = transactionId,
amount = -cmd.amount,
remainingAmount = amount - cmd.amount
)
applyEvent(e)
return e
}
111. 68
var amount by Delegates.notNull<Int>()
var revoked = false
@CommandHandler
fun handle(cmd: RedeemCardCommand): GiftCardTransaction {
if (revoked)
throw IllegalStateException("card has been revoked")
if (cmd.amount <= 0)
throw IllegalArgumentException(
"invalid amount ${cmd.amount}")
if (cmd.amount > amount)
throw IllegalArgumentException(
„insufficient card credit")
val transactionId = newTransactionId()
val e = RedeemedEvent(
id = id,
transactionId = transactionId,
amount = -cmd.amount,
remainingAmount = amount - cmd.amount
)
applyEvent(e)
return e
}
• Der Command Handler führ
eine Validierung des
Commands durch
112. 69
var amount by Delegates.notNull<Int>()
var revoked = false
@CommandHandler
fun handle(cmd: RedeemCardCommand): GiftCardTransaction {
if (revoked)
throw IllegalStateException("card has been revoked")
if (cmd.amount <= 0)
throw IllegalArgumentException(
"invalid amount ${cmd.amount}")
if (cmd.amount > amount)
throw IllegalArgumentException(
„insufficient card credit")
val transactionId = newTransactionId()
val e = RedeemedEvent(
id = id,
transactionId = transactionId,
amount = -cmd.amount,
remainingAmount = amount - cmd.amount
)
applyEvent(e)
return e
}
• Der Command Handler führ
eine Validierung des
Commands durch
• Nach erfolgter Validierung
wird ein Event mit dem
neuen Zustand erzeugt
113. 70
var amount by Delegates.notNull<Int>()
var revoked = false
@CommandHandler
fun handle(cmd: RedeemCardCommand): GiftCardTransaction {
if (revoked)
throw IllegalStateException("card has been revoked")
if (cmd.amount <= 0)
throw IllegalArgumentException(
"invalid amount ${cmd.amount}")
if (cmd.amount > amount)
throw IllegalArgumentException(
„insufficient card credit")
val transactionId = newTransactionId()
val e = RedeemedEvent(
id = id,
transactionId = transactionId,
amount = -cmd.amount,
remainingAmount = amount - cmd.amount
)
applyEvent(e)
return e
}
• Der Command Handler führ
eine Validierung des
Commands durch
• Nach erfolgter Validierung
wird ein Event mit dem
neuen Zustand erzeugt
116. 73
@Entity
data class GiftCardTransactionEntity(
@Id
@GeneratedValue
var id: Long? = null,
var giftCardId: String,
var transactionId: Int,
var amount: Int,
@Column(length = 100)
var description: String
)
@Entity
data class GiftCardEntity(
@Id
var id: String,
var revoked: Boolean = false,
var amount: Int = 0
)
type Query {
giftCard(id: ID!): GiftCard
}
type GiftCard {
id: ID!
amount: Int!
revoked: Boolean!
transactions: [GiftCardTransaction!]!
}
type GiftCardTransaction {
transactionId: ID!
amount: Int!
description: String!
}
117. 74
class GiftCardTransactionRepositoryUpdater(private val repo: GiftCardTransactionRepository) {
@EventHandler
fun on(e: CardIssuedEvent) {
// we create a "virtual" transaction that represents the issuing
repo.save(
GiftCardTransactionEntity(
giftCardId = e.id,
transactionId = 0,
amount = e.amount,
remainingAmount = e.amount,
description = "Gift Card issued"
)
)
}
@EventHandler
fun on(e: GiftCardTransaction) {
repo.save(
GiftCardTransactionEntity(
giftCardId = e.id,
transactionId = e.transactionId,
amount = e.amount,
description = when(e) {
is RedeemedEvent -> "Redeemed"
is CreditIncreasedEvent -> "Credit increased"
is TransactionRevokedEvent -> "Transaction ${e.revokedTransactionId} revoked"
else -> ""
}
)
)
}
}
118. 75
@Controller
class QueryController(
private val giftCardRepository: GiftCardRepository,
private val giftCardTransactionRepository: GiftCardTransactionRepository
) {
@QueryMapping
fun giftCard(@Argument id: String) = giftCardRepository
.findById(id).orElseThrow {
GraphqlErrorException.Builder()
.errorClassification(ErrorType.NOT_FOUND)
.message("Gift card with id $id not found")
.build()
}
@SchemaMapping(typeName = "GiftCard", field = "transactions")
fun transactions(parent: GiftCardEntity) =
giftCardTransactionRepository
.findByGiftCardIdOrderByTransactionId(parent.id)
}
119. 76
Thank you for listening!
Any Questions?
https://blog.digitalfrontiers.de
https://www.digitalfrontiers.de
@tellme_francois
github.com/fernanfs
François Fernandès
Senior Solution Architect
Photo by Matt Walsh on Unsplash