SlideShare a Scribd company logo
GraphQL - when REST API is
not enough - lessons learned
Part 1
Marcin Stachniuk
8 October 2018
Marcin Stachniuk
mstachniuk.github.io
/mstachniuk/graphql-java-example
@MarcinStachniuk
wroclaw.jug.pl
shipkit.org
Agenda
11:00
● Why?
● Concepts
● Basics
12:00 Lunch
13:00
● GraphQL in Java
● Lessons learned
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
Monady w .NET – i tak używasz, więc dowiedz się, o co chodzi.
Mateusz Stasch
Rewolucja w analizie danych z RevoscaleR oraz RevoscalePy
Tomasz Krawczyk
Scale it the easy way - introduction to micro frontends
Jakub Holak
Who is using REST?
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
REST - REpresentational State Transfer
https://api.example.com/customers/123
DELETE
PUT
POST
GET
PATCH
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
REST fixed response
GET /customers/111
{
"customer": {
"id": "111",
"name": "John Doe",
"email": "john@doe.com",
"company": {
"id": "222"
},
"orders": [
{
"id": "333"
},
{
"id": "444"
}
]
}
}
{
"customer": {
"id": "111",
"name": "John Doe",
"email": "john@doe.com",
"company": {
"href": "https://api.example.com/companies/222"
},
"orders": [
{
"href": "https://api.example.com/orders/333"
},
{
"href": "https://api.example.com/orders/444"
}
]
}
}
RE
ST
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
REST consequences: several roundtrips
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
U
nderFetching
REST response with nested data
GET /customers/111
{
"customer": {
"id": "111",
"name": "John Doe",
"email": "john@doe.com",
"company": {
"id": "222",
"name": "My Awesome Corporation",
"website": "MyAwesomeCorporation.com"
},
"orders": [
{
"id": "333",
"status": "delivered",
"items": [
{
"id": "555",
"name": "Silver Bullet",
"amount": "42",
"price": "10000000",
"currency": "USD",
"producer": {
"id": "777",
"name": "Lorem Ipsum",
"website": "LoremIpsum.com"
}
}
]
},
{
"id": "444",
"name": "Golden Hammer",
"amount": "5",
"price": "10000",
"currency": "USD",
"producer": {
...
}
}
] } }
RE
ST
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
O
verFetching
REST response with nested data and limit fields
GET /customers/111?fields=name,company/*,orders.status,orders.items(name,producer/name)
{
"customer": {
"id": "111",
"name": "John Doe",
"email": "john@doe.com",
"company": {
"id": "222",
"name": "My Awesome Corporation",
"website": "MyAwesomeCorporation.com"
},
"orders": [
{
"id": "333",
"status": "delivered",
"items": [
{
"id": "555",
"name": "Silver Bullet",
"amount": "42",
"price": "10000000",
"currency": "USD",
"producer": {
"id": "777",
"name": "Lorem Ipsum",
"website": "LoremIpsum.com"
}
}
]
},
{
"id": "444",
"name": "Golden Hammer",
"amount": "5",
"price": "10000",
"currency": "USD",
"producer": {
...
}
}
] } }
RE
ST
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
REST response with projection
GET /customers/111?projection=customerPreview
{
"customer": {
"id": "111",
"name": "John Doe",
"email": "john@doe.com",
"company": {
"id": "222",
"name": "My Awesome Corporation",
"website": "MyAwesomeCorporation.com"
},
"orders": [
{
"id": "333",
"status": "delivered",
"items": [
{
"id": "555",
"name": "Silver Bullet",
"amount": "42",
"price": "10000000",
"currency": "USD",
"producer": {
"id": "777",
"name": "Lorem Ipsum",
"website": "LoremIpsum.com"
}
}
]
},
{
"id": "444",
"name": "Golden Hammer",
"amount": "5",
"price": "10000",
"currency": "USD",
"producer": {
...
}
}
] } }
RE
ST
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
Different clients - different needs
/web /iphone /android /tv
Application
Web iPhone Android TV
RE
ST
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
Different clients - different needs
/web /iphone /android /tv
Application
Web iPhone Android TV
Content-Type: application/vnd.myawesomecorporation.com+v1+web+json
iphone
android
tv
RE
ST
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
Different clients - different needs
/web /iphone /android /tv
Application
Web iPhone Android TV
Content-Type: application/vnd.myawesomecorporation.com+v1+web+json
iphone
android
tv
RE
ST
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
REST contract is rigid
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
Platform Architecture
Platform
App 1 App 2
Customer
App X...
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
REST API Versioning
GET /v2/customers/111RE
ST
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
GET /customers/111?v=v2RE
ST
GET /customers/111 Accept header: application/vnd.myapp.2+jsonRE
ST
GET /customers/111 Custom header: x-ms-version:2RE
ST
● How to migrate?
● How to document?
● Is versionless API possible?
● What about continuous evolution of API?
Modularisation at UI
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
New Frontend Framework
ReactJS
Relay GraphQL
TypeScript
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
GraphQL
● Graph Query Language
● Published by Facebook in 2015
● Growth from Facebook Graph API
● Reference implementation in JavaScript
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
GraphQL main concepts
● One endpoint for all operations
● Always define in request what you need
● Queries, Mutations and Subscriptions
● Defined by schema
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
Data is a graph
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
GraphQL time for demo
● Fragments
● Aliases
● Directives
● Interfaces
● Unions
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
● Query
● Syntax Error
● Mutation
● Operation name
● Variables
GraphQL Simple API
GET /customers/2?fields=id,name,email
type Customer {
#fields with ! are not null
id: ID!
name: String!
email: String!
}
type Query {
customer(id: String!): Customer!
}
{
"data": {
"customer": {
"id": "2",
"name": "name",
"email": "a@b.com"
}
}
}
{
customer(id: "2") {
id
name
email
}
}
RE
ST
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
GraphQL Bad Request
GET /custo!@#$ -> 404
{
"data": null,
"errors": [
{
"message": "Invalid Syntax",
"locations": [
{
"line": 2,
"column": 8
}
],
"errorType": "InvalidSyntax",
"path": null,
"extensions": null
} ] }
{
custo!@#$
}
RE
ST
http.cat/200
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
Go back to the roots
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
GraphQL Simple API
GET /customers/2?fields=id,name,email,company(id,name)
type Customer {
id: ID!
name: String!
email: String!
company: Company
}
type Company {
id: ID!
name: String!
website: String!
}
type Query {
customer(id: String!): Customer!
}
{
"data": {
"customer": {
"id": "2",
"name": "name",
"email": "a@b.com",
"company": {
"id": "211",
"name": "Company Corp."
}
}
}
}
{
customer(id: "2") {
id
name
email
company {
id
name
}
}
}
RE
ST
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
GraphQL Simple API
GET /customers/2?fields=id,name,email,orders(id,status)
type Customer {
id: ID!
name: String!
email: String!
company: Company
orders: [Order]
}
type Order {
id: ID!
status: Status
}
enum Status {
NEW, CANCELED, DONE
}
{
"data": {
"customer": {
"id": "2",
"name": "name",
"orders": [
{
"id": "55",
"status": "NEW"
},
{
"id": "66",
"status": "DONE"
}
] } } }
{
customer(id: "2") {
id
name
orders {
id
status
}
}
}
RE
ST
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
GraphQL mutations
input CreateCustomerInput {
name: String
email: String
clientMutationId: String!
}
type CreateCustomerPayload {
customer: Customer
clientMutationId: String!
}
type Mutation {
createCustomer(input: CreateCustomerInput):
CreateCustomerPayload!
}
{
"data": {
"createCustomer": {
"customer": {
"id": "40",
},
"clientMutationId":
"123"
}
}
}
POST /customers PUT /customers/123 DELETE /customers/123 PATCH /customers/123
mutation {
createCustomer(input: {
name: "MyName"
email: "me@me.com"
clientMutationId: "123"
}) {
customer {
id
}
clientMutationId
}
}
RE
ST
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
GraphQL mutations + operation name
mutation crCust {
createCustomer(input: {
name: "MyName"
email: "me@me.com"
clientMutationId: "123"
}) {
customer {
id
}
clientMutationId
}
}
{
"data": {
"createCustomer": {
"customer": {
"id": "40",
},
"clientMutationId":
"123"
}
}
}
POST /customers PUT /customers/123 DELETE /customers/123 PATCH /customers/123RE
ST
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
mutation {
createCustomer(input: {
name: "MyName"
email: "me@me.com"
clientMutationId: "123"
}) {
customer {
id
}
clientMutationId
}
}
GraphQL Variables
{
"data": {
"createCustomer": {
"customer": {
"id": "40",
},
"clientMutationId":
"123"
}
}
}
POST /customers PUT /customers/123 DELETE /customers/123 PATCH /customers/123
mutation crCust {
createCustomer(input: {
name: "MyName"
email: "me@me.com"
clientMutationId: "123"
}) {
customer {
id
}
clientMutationId
}
}
RE
ST
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
mutation crCust ($input: CreateCustInput) {
createCustomer(input: $input) {
customer {
id
}
clientMutationId
}
}
{
"input": {
"name": "MyName 2",
"email": "me2@me.com",
"clientMutationId": "123"
}
}
GraphQL Aliases
GET /customers/2?fields=id,name,email +
{
"data": {
"cust1": {
"id": "2",
"name": "name",
"email": "a@b.com"
},
"cust2": {
"id": "3",
"name": "John Doe",
"email": "john@doe.com"
}
}
}
query get2Cust {
cust1: customer(id: "2") {
id
name
email
}
cust2: customer(id: "3") {
id
name
email
}
}
RE
ST
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
GET /customers/3?fields=id,name,emailRE
ST
GraphQL Fragment
GET /customers/2?fields=id,name,email +
{
"data": {
"cust1": {
"id": "2",
"name": "name",
"email": "a@b.com"
},
"cust2": {
"id": "3",
"name": "John Doe",
"email": "john@doe.com"
}
}
}
query get2Cust {
cust1: customer(id: "2") {
... frag1
}
cust2: customer(id: "3") {
... frag1
}
}
fragment frag1 on Customer {
id
name
email
}
RE
ST
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
GET /customers/3?fields=id,name,emailRE
ST
GraphQL Directive
GET /customers/2?fields=id,name
{
"data": {
"customer": {
"id": "2",
"name": "name"
}
}
}
query getCust ($showEmail: Boolean!) {
customer(id: "2") {
id
name
email @include(if: $showEmail)
}
}
{
"showEmail": false
}
RE
ST
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
GraphQL Interface
GET /users?fields=id,name,superAdmin,permissions
type Query {
users: [User]
}
interface User {
id: ID!
name: String!
email: String!
}
type Admin implements User {
superAdmin: Boolean! // + id...
}
type Moderator implements User {
permissions: [String] // + id...
}
{
"data": {
"users": [
{
"id": "777",
"name": "Admin a",
"superAdmin": true
},
{
"id": "888",
"name": "Moderator",
"permissions": [
"Delete Customer",
"Delete comment"
]}]}}
query getUsers {
users {
... on Admin {
id
name
superAdmin
}
... on Moderator {
id
name
permissions
}
}
}
RE
ST
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
GraphQL Union
GET /search?input=a?fields=typename,name
type Query {
search(input: String):
[SearchResult]
}
union SearchResult =
Customer |
Admin |
Moderator
{
"data": {
"search": [
{
"__typename": "Customer",
"name": "name"
},
{
"__typename": "Admin",
"name": "Admin a"
},
{
"__typename": "Moderator",
"name": "Moderator"
}]}}
query searchSmth {
search(input: "a") {
__typename
... on Customer {
name
}
... on Admin {
name
}
... on Moderator {
name
}
}
}
RE
ST
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
Q&A
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
Feedback
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
To be continued...
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
GraphQL - when REST API is
not enough - lessons learned
Part 2
Marcin Stachniuk
8 October 2018
Agenda
11:00
● Why?
● Concepts
● Basics
12:00 Lunch
13:00
● GraphQL in Java
● Lessons learned
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
Serverless .NET on AWS
Wojciech Gawroński
Lunch
GraphQL
● Graph Query Language
● Published by Facebook in 2015
● Growth from Facebook Graph API
● Reference implementation in JavaScript
● First version of Java Library: 18 Jul 2015
https://github.com/graphql-java/graphql-java
● First usage: 21 Sep 2015
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
Lessons Learned #1
Never add a library to your project
few days after init release
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
● No community
● A lot of bugs
● Bad documentation
● Strict following reference
implementation and specification
DO NOT TRY
THIS AT WORK
GraphQL Simple API
GET /customers/2?fields=id,name,email,orders(id,status)
type Customer {
id: ID!
name: String!
email: String!
company: Company
orders: [Order]
}
type Order {
id: ID!
status: Status
}
enum Status {
NEW, CANCELED, DONE
}
{
"data": {
"customer": {
"id": "2",
"name": "name",
"orders": [
{
"id": "55",
"status": "NEW"
},
{
"id": "66",
"status": "DONE"
}
] } } }
{
customer(id: "2") {
id
name
orders {
id
status
}
}
}
RE
ST
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
How to implement DataFetcher for queries
GET /customers/2?fields=id,name,email,orders(id,status)
@Component
public class CustomerFetcher extends PropertyDataFetcher<Customer> {
@Autowired
private CustomerService customerService;
@Override
public Customer get(DataFetchingEnvironment environment) {
String id = environment.getArgument("id");
return customerService.getCustomerById(id);
}
}
RE
ST
{
customer(id: "2") {
id
name
orders {
id
status
}
}
}
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
How to implement DataFetcher for queries
GET /customers/2?fields=id,name,email,orders(id,status)
public class Customer {
private String id;
private String name;
private String email; // getters are not required
}
RE
ST
{
customer(id: "2") {
id
name
orders {
id
status
}
}
}
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
public class OrderDataFetcher extends PropertyDataFetcher<List<Order>> {
@Override
public List<Order> get(DataFetchingEnvironment environment) {
Customer source = environment.getSource();
String customerId = source.getId();
return orderService.getOrdersByCustomerId(customerId);
}
}
GraphQL mutations
input CreateCustomerInput {
name: String
email: String
clientMutationId: String!
}
type CreateCustomerPayload {
customer: Customer
clientMutationId: String!
}
type Mutation {
createCustomer(input: CreateCustomerInput):
CreateCustomerPayload!
}
{
"data": {
"createCustomer": {
"customer": {
"id": "40",
},
"clientMutationId":
"123"
}
}
}
POST /customers PUT /customers/123 DELETE /customers/123 PATCH /customers/123
mutation {
createCustomer(input: {
name: "MyName"
email: "me@me.com"
clientMutationId: "123"
}) {
customer {
id
}
clientMutationId
}
}
RE
ST
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
How to implement DataFetcher for mutations
POST /customers PUT /customers/123 DELETE /customers/123 PATCH /customers/123
@Component
public class CreateCustomersFetcher extends
PropertyDataFetcher<CreateCustomersPayload> {
@Override
public CreateCustomerPayload get(DataFetchingEnvironment env) {
Map<String, Object> input = env.getArgument("input");
String name = (String) input.get("name");
String email = (String) input.get("email");
String clientMutationId = (String) input.get("clientMutationId");
Customer customer = customerService.create(name, email);
return new CreateCustomerPayload(customer, clientMutationId);
}
RE
ST
mutation {
createCustomer(input: {
name: "MyName"
email: "me@me.com"
clientMutationId: "123"
}) {
customer {
id
}
clientMutationId
}
}
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
In case Interfaces and Unions - Type Resolver is needed
public class UserTypeResolver implements TypeResolver {
@Override
public GraphQLObjectType getType(TypeResolutionEnvironment env) {
Object javaObject = env.getObject();
if (javaObject instanceof Admin) {
return env.getSchema().getObjectType("Admin");
} else if (javaObject instanceof Moderator) {
return env.getSchema().getObjectType("Moderator");
} else {
throw new RuntimeException("Unknown type " + javaObject.getClass().getName());
}
}
}
public interface User {...}
public class Admin implements User {...}
public class Moderator implements User {...}
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
Glue everything together
RuntimeWiring runtimeWiring = RuntimeWiring.newRuntimeWiring()
.type("Query", builder ->
builder.dataFetcher("customer", customerFetcher))
.type("Mutation", builder ->
builder.dataFetcher("createCustomer", createCustomerFetcher))
.type(newTypeWiring("User")
.typeResolver(new UserTypeResolver())
.build())
...
.build();
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
Abstraction over GraphQL Java
Our abstraction
Data Fetcher 2
Inputs mapping to objects
Schema definition
Pagination
...
Data Fetcher 1 Data Fetcher N...
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
Lessons Learned #2
Abstraction is not good if you don’t understand
how it works under the hood
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
● Copy paste errors
● Wrong usage
● Hard to update to new version
GraphQL type system
How to define your schema?
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
Code First approach
private GraphQLFieldDefinition customerDefinition() {
return GraphQLFieldDefinition.newFieldDefinition()
.name("customer")
.argument(GraphQLArgument.newArgument()
.name("id")
.type(new GraphQLNonNull(GraphQLString)))
.type(new GraphQLNonNull(GraphQLObjectType.newObject()
.name("Customer")
.field(GraphQLFieldDefinition.newFieldDefinition()
.name("id")
.description("fields with ! are not null")
.type(new GraphQLNonNull(GraphQLID))
.build())
….
.build()))
.dataFetcher(customerFetcher)
.build();
}
Schema First approach
type Query {
customer(id: String!): Customer!
}
type Customer {
#fields with ! are not null
id: ID!
name: String!
email: String!
company: Company
orders: [Order]
}
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
Code First approach - How to build
Introspection
query
Introspection
response
Replace Relay
definitions
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
Typescript relay
plugin
Schema First approach
type Customer {
# fields with ! are required
id: ID!
name: String!
email: String!
company: Company
orders: [Order]
}
*.graphqls
SchemaParser schemaParser = new SchemaParser();
File file = // ...
TypeDefinitionRegistry registry = schemaParser.parse(file);
SchemaGenerator schemaGenerator = new SchemaGenerator();
RuntimeWiring runtimeWiring = RuntimeWiring.newRuntimeWiring()
.type("Query", builder ->
builder.dataFetcher("customer", customerFetcher))
// ...
.build();
return schemaGenerator.makeExecutableSchema(registry, runtimeWiring);
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
Schema First approach - project building diagram
model.graphqls
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
GraphQL SPQR
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
https://github.com/leangen/graphql-spqr
SPQR - Senatus Populusque Romanus
SPQR approach
public class UserService {
@GraphQLQuery(name = "user")
public User getById(@GraphQLArgument(name = "id") Integer id) {
//...
}
}
public class Customer {
//...
@GraphQLQuery(name = "name", description = "A person's name")
public String getName() {
return name;
}
}
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
Lessons Learned #3
Code First Approach is the worst
Schema First Approach:
● Easy to maintain and
understand
● Helps organise work
● Demo schema is 3x smaller
GraphQL SPQR - ?
Code First approach:
● Hard to maintain
● It was the only way at the
beginning to define a schema
● No possibility to mix both
● No easy way to migrate to
Schema First
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
From Code First to Schema First migration
https://github.com/mstachniuk/graphql-schema-from-introspection-generator
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
GraphQL - How to define pagination, filtering, sorting?
Pagination:
● before, after
● offset, limit
Filtering:
● filter(name: “Bob” email: “%@gmail.com”)
● filter: {
OR: [{
email: “%@gmail.com”
}]
}, name: “Bob”
}
Sorting:
● orderBy: ASC, DESC
● sort: NEWEST, IMPORTANCE
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
Lessons Learned #4
GraphQL is not full query language
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
● Flexibility
● Less common conventions
● Dgraph.io created GraphQL+-
GraphQL downsides
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
GraphQL downsides: N+1 problem
{
customers { 1 call
id
name
orders { n calls
id
status
}
}
}
java-dataloader
● Add async BatchLoader
● Add caching
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
graphQL = GraphQL.newGraphQL(schema)
.queryExecutionStrategy(
new BatchedExecutionStrategy())
.build();
+ @Batched in DataFetcher#get()
Lessons Learned #5
If you have N + 1 problem
use java-dataloader
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
Complex Queries
fragment TypeRef on __Type {
kind
name
ofType {
kind
name
ofType {
kind
name
...
}
}
}
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
graphQL = GraphQL.newGraphQL(schema)
.instrumentation(
new ChainedInstrumentation(asList(
new MaxQueryComplexityInstrumentation(200),
new MaxQueryDepthInstrumentation(20)
)))
.build();
Lessons Learned #6
Performance killer?
Define instrumentation!
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
GraphQL downsides: Bad GraphQL API definition - examples
{
customer(id: "2") { … }
customerFull(id: "2") { … }
customerFull2(id: "2") { … }
customerWithDetails(id: "2") { … }
...
}
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
{
customer(id: "2") {
id
name
orders {
id
status
}
}
}
GraphQL downsides: Bad GraphQL API definition - examples
query getUser {
user(id: "123") {
... on Admin {
id
superAdmin
}
... on Moderator {
id
permissions
}
}
}
{
admin(id: "123") {
id
superAdmin
}
moderator(id: "123") {
id
permissions
}
}
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
GraphQL downsides: Bad GraphQL API definition - examples
{
orders (input: {
status: "NEW"
first: "2"
offset: "3"
}, first: "1", offset: "3") {
Items { … }
}
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
Lessons Learned #7
Thinking shift is a key
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
● Let’s think in graphs and NOT in
endpoints / resources / entities / DTOs
● Bad design of our API
GraphQL Testing
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
Testing GraphQL
@SpringBootTest
@ContextConfiguration(classes = Main)
class CustomerFetcherSpec extends Specification {
@Autowired
GraphQLSchema graphQLSchema
GraphQL graphQL
def setup() {
graphQL = GraphQL.newGraphQL(graphQLSchema).build()
}
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
Testing GraphQL
def "should get customer by id"() {
given:
def query = """{ customer(id: "2") { … } }"""
def expected = [ "customer": [ … ] ]
when:
def result = graphQL.execute(query)
then:
result.data == expected
}
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
Lessons Learned #8
Testing is easy
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
Trap Adventure 2 - "The Hardest Retro Game"
Versioning
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
GraphQL takes a strong opinion on avoiding
versioning by providing the tools for the
continuous evolution of a GraphQL schema.
Src: https://graphql.org/learn/best-practices/#versioning
Versioning
type Query {
customer(id: String!): Customer! @deprecated(reason: "not used ...")
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
Lessons Learned #9
Versioning is not a problem
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
GET /v2/customers/111RE
ST
GET /customers/111?v=v2RE
ST
GET /customers/111 Accept header: application/vnd.myapp.2+jsonRE
ST
GET /customers/111 Custom header: x-ms-version:2RE
ST
Versioning problem is different
Tools
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
Tools GraphiQL
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
Tools Relay
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
user(...) {
photo(width: "120", height: "120")
}
user(...) {
name
}
user(...) {
email
}
user(...) {
name
email
photo(width: "120", height: "120")
}
Distelli/graphql-apigen
https://github.com/Distelli/graphql-apigen
Generate Java APIs with GraphQL Schemas in order to
facilitate "schema first" development.
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
GraphQL Java Tools
https://github.com/graphql-java/graphql-java-tools
Map GraphQL schema to POJOs
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
More libraries and projects related to graphql-java
https://github.com/graphql-java/awesome-graphql-java
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
● Generates a GraphQL schema from a JDBC data source
● Annotations-based syntax for GraphQL schema definition
● JPA Implementation of GraphQL (builds on graphql-java)
● And more examples
Apollo
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
Build a universal GraphQL API on top of your existing REST
APIs, so you can ship new application features fast without
waiting on backend changes.
Lessons Learned #10
Tooling is nice
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
now
Summary
GraphQL Pros:
● Nice alternative to REST
● It can be used together with REST
● Good integration with Relay / ReactJS
● You get exactly what you want to get
● Good for API with different clients
● Good to use on top of existing API
● Self documented
● Easy testing
● Nice tooling
● Thin layer
GraphQL Cons:
● High entry barrier
● Hard to return simple Map
● Not well know (yet)
● Performance overhead
● A lot of similar code to write
● No Operation Idempotency
● No Cache & Security
● No Authorisation
● Always HTTP 200 -
unsupported tools
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
Nothing is a silver bullet
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
Q&A
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
Feedback
@MarcinStachniukGraphQL - when REST API is not enough - lessons learned
GraphQL - when REST API is
not enough - lessons learned
Part 2
Marcin Stachniuk
8 October 2018
Thank
you!

More Related Content

What's hot

GraphQL - gdy API RESTowe to za mało
GraphQL - gdy API RESTowe to za małoGraphQL - gdy API RESTowe to za mało
GraphQL - gdy API RESTowe to za mało
MarcinStachniuk
 
BruJUG Brussels GraphQL when RESR API is to less - lessons learned
BruJUG Brussels GraphQL when RESR API is to less - lessons learnedBruJUG Brussels GraphQL when RESR API is to less - lessons learned
BruJUG Brussels GraphQL when RESR API is to less - lessons learned
MarcinStachniuk
 
API Docs Made Right / RAML - Swagger rant
API Docs Made Right / RAML - Swagger rantAPI Docs Made Right / RAML - Swagger rant
API Docs Made Right / RAML - Swagger rant
Vladimir Shulyak
 
[@IndeedEng] Building Indeed Resume Search
[@IndeedEng] Building Indeed Resume Search[@IndeedEng] Building Indeed Resume Search
[@IndeedEng] Building Indeed Resume Search
indeedeng
 
@IndeedEng: Tokens and Millicents - technical challenges in launching Indeed...
@IndeedEng:  Tokens and Millicents - technical challenges in launching Indeed...@IndeedEng:  Tokens and Millicents - technical challenges in launching Indeed...
@IndeedEng: Tokens and Millicents - technical challenges in launching Indeed...
indeedeng
 
Hypermedia APIs and HATEOAS
Hypermedia APIs and HATEOASHypermedia APIs and HATEOAS
Hypermedia APIs and HATEOAS
Vladimir Tsukur
 
Hypermedia APIs and HATEOAS / Wix Engineering
Hypermedia APIs and HATEOAS / Wix EngineeringHypermedia APIs and HATEOAS / Wix Engineering
Hypermedia APIs and HATEOAS / Wix Engineering
Vladimir Tsukur
 
Pascarello_Investigating JavaScript and Ajax Security
Pascarello_Investigating JavaScript and Ajax SecurityPascarello_Investigating JavaScript and Ajax Security
Pascarello_Investigating JavaScript and Ajax Security
amiable_indian
 
Frank Mantek Google G Data
Frank Mantek Google G DataFrank Mantek Google G Data
Frank Mantek Google G Datadeimos
 
Simplify Access to Data from Pivotal GemFire Using the GraphQL (G2QL) Extension
Simplify Access to Data from Pivotal GemFire Using the GraphQL (G2QL) ExtensionSimplify Access to Data from Pivotal GemFire Using the GraphQL (G2QL) Extension
Simplify Access to Data from Pivotal GemFire Using the GraphQL (G2QL) Extension
VMware Tanzu
 
[@IndeedEng] Logrepo: Enabling Data-Driven Decisions
[@IndeedEng] Logrepo: Enabling Data-Driven Decisions[@IndeedEng] Logrepo: Enabling Data-Driven Decisions
[@IndeedEng] Logrepo: Enabling Data-Driven Decisions
indeedeng
 

What's hot (11)

GraphQL - gdy API RESTowe to za mało
GraphQL - gdy API RESTowe to za małoGraphQL - gdy API RESTowe to za mało
GraphQL - gdy API RESTowe to za mało
 
BruJUG Brussels GraphQL when RESR API is to less - lessons learned
BruJUG Brussels GraphQL when RESR API is to less - lessons learnedBruJUG Brussels GraphQL when RESR API is to less - lessons learned
BruJUG Brussels GraphQL when RESR API is to less - lessons learned
 
API Docs Made Right / RAML - Swagger rant
API Docs Made Right / RAML - Swagger rantAPI Docs Made Right / RAML - Swagger rant
API Docs Made Right / RAML - Swagger rant
 
[@IndeedEng] Building Indeed Resume Search
[@IndeedEng] Building Indeed Resume Search[@IndeedEng] Building Indeed Resume Search
[@IndeedEng] Building Indeed Resume Search
 
@IndeedEng: Tokens and Millicents - technical challenges in launching Indeed...
@IndeedEng:  Tokens and Millicents - technical challenges in launching Indeed...@IndeedEng:  Tokens and Millicents - technical challenges in launching Indeed...
@IndeedEng: Tokens and Millicents - technical challenges in launching Indeed...
 
Hypermedia APIs and HATEOAS
Hypermedia APIs and HATEOASHypermedia APIs and HATEOAS
Hypermedia APIs and HATEOAS
 
Hypermedia APIs and HATEOAS / Wix Engineering
Hypermedia APIs and HATEOAS / Wix EngineeringHypermedia APIs and HATEOAS / Wix Engineering
Hypermedia APIs and HATEOAS / Wix Engineering
 
Pascarello_Investigating JavaScript and Ajax Security
Pascarello_Investigating JavaScript and Ajax SecurityPascarello_Investigating JavaScript and Ajax Security
Pascarello_Investigating JavaScript and Ajax Security
 
Frank Mantek Google G Data
Frank Mantek Google G DataFrank Mantek Google G Data
Frank Mantek Google G Data
 
Simplify Access to Data from Pivotal GemFire Using the GraphQL (G2QL) Extension
Simplify Access to Data from Pivotal GemFire Using the GraphQL (G2QL) ExtensionSimplify Access to Data from Pivotal GemFire Using the GraphQL (G2QL) Extension
Simplify Access to Data from Pivotal GemFire Using the GraphQL (G2QL) Extension
 
[@IndeedEng] Logrepo: Enabling Data-Driven Decisions
[@IndeedEng] Logrepo: Enabling Data-Driven Decisions[@IndeedEng] Logrepo: Enabling Data-Driven Decisions
[@IndeedEng] Logrepo: Enabling Data-Driven Decisions
 

Similar to GraphQL - when REST API is to less - lessons learned

GraphQL - an elegant weapon... for more civilized age
GraphQL - an elegant weapon... for more civilized ageGraphQL - an elegant weapon... for more civilized age
GraphQL - an elegant weapon... for more civilized age
Bartosz Sypytkowski
 
React & GraphQL
React & GraphQLReact & GraphQL
React & GraphQL
Nikolas Burk
 
Wroclaw GraphQL - GraphQL in Java
Wroclaw GraphQL - GraphQL in JavaWroclaw GraphQL - GraphQL in Java
Wroclaw GraphQL - GraphQL in Java
MarcinStachniuk
 
Overview of GraphQL & Clients
Overview of GraphQL & ClientsOverview of GraphQL & Clients
Overview of GraphQL & Clients
Pokai Chang
 
Building Serverless GraphQL Backends
Building Serverless GraphQL BackendsBuilding Serverless GraphQL Backends
Building Serverless GraphQL Backends
Nikolas Burk
 
The Serverless GraphQL Backend Architecture
The Serverless GraphQL Backend ArchitectureThe Serverless GraphQL Backend Architecture
The Serverless GraphQL Backend Architecture
Nikolas Burk
 
MongoDB World 2019: Building a GraphQL API with MongoDB, Prisma, & TypeScript
MongoDB World 2019: Building a GraphQL API with MongoDB, Prisma, & TypeScriptMongoDB World 2019: Building a GraphQL API with MongoDB, Prisma, & TypeScript
MongoDB World 2019: Building a GraphQL API with MongoDB, Prisma, & TypeScript
MongoDB
 
Connecting the Dots: Kong for GraphQL Endpoints
Connecting the Dots: Kong for GraphQL EndpointsConnecting the Dots: Kong for GraphQL Endpoints
Connecting the Dots: Kong for GraphQL Endpoints
Julien Bataillé
 
REST to GraphQL migration: Pros, cons and gotchas
REST to GraphQL migration: Pros, cons and gotchasREST to GraphQL migration: Pros, cons and gotchas
REST to GraphQL migration: Pros, cons and gotchas
Alexey Ivanov
 
GraphQL in an Age of REST
GraphQL in an Age of RESTGraphQL in an Age of REST
GraphQL in an Age of REST
Yos Riady
 
The Magic of LINE 購物 Testing
The Magic of LINE 購物 TestingThe Magic of LINE 購物 Testing
The Magic of LINE 購物 Testing
LINE Corporation
 
Better APIs with GraphQL
Better APIs with GraphQL Better APIs with GraphQL
Better APIs with GraphQL
Josh Price
 
Rest vs graphql - why choose
Rest vs graphql - why chooseRest vs graphql - why choose
Rest vs graphql - why choose
Tally Barak
 
Diving into GraphQL, React & Apollo
Diving into GraphQL, React & ApolloDiving into GraphQL, React & Apollo
Diving into GraphQL, React & Apollo
Nikolas Burk
 
Tutorial: Building a GraphQL API in PHP
Tutorial: Building a GraphQL API in PHPTutorial: Building a GraphQL API in PHP
Tutorial: Building a GraphQL API in PHP
Andrew Rota
 
API Technical Writing
API Technical WritingAPI Technical Writing
API Technical Writing
Sarah Maddox
 
Elasticsearch
ElasticsearchElasticsearch
Elasticsearch
Anurag Srivastava
 
Using GraphQL for the next generation of the Holdsport APIUsing GraphQL for t...
Using GraphQL for the next generation of the Holdsport APIUsing GraphQL for t...Using GraphQL for the next generation of the Holdsport APIUsing GraphQL for t...
Using GraphQL for the next generation of the Holdsport APIUsing GraphQL for t...
Jørgen Orehøj Erichsen
 
MongoDB.local Berlin: Building a GraphQL API with MongoDB, Prisma and Typescript
MongoDB.local Berlin: Building a GraphQL API with MongoDB, Prisma and TypescriptMongoDB.local Berlin: Building a GraphQL API with MongoDB, Prisma and Typescript
MongoDB.local Berlin: Building a GraphQL API with MongoDB, Prisma and Typescript
MongoDB
 
REST API に疲れたあなたへ贈る GraphQL 入門
REST API に疲れたあなたへ贈る GraphQL 入門REST API に疲れたあなたへ贈る GraphQL 入門
REST API に疲れたあなたへ贈る GraphQL 入門
Keisuke Tsukagoshi
 

Similar to GraphQL - when REST API is to less - lessons learned (20)

GraphQL - an elegant weapon... for more civilized age
GraphQL - an elegant weapon... for more civilized ageGraphQL - an elegant weapon... for more civilized age
GraphQL - an elegant weapon... for more civilized age
 
React & GraphQL
React & GraphQLReact & GraphQL
React & GraphQL
 
Wroclaw GraphQL - GraphQL in Java
Wroclaw GraphQL - GraphQL in JavaWroclaw GraphQL - GraphQL in Java
Wroclaw GraphQL - GraphQL in Java
 
Overview of GraphQL & Clients
Overview of GraphQL & ClientsOverview of GraphQL & Clients
Overview of GraphQL & Clients
 
Building Serverless GraphQL Backends
Building Serverless GraphQL BackendsBuilding Serverless GraphQL Backends
Building Serverless GraphQL Backends
 
The Serverless GraphQL Backend Architecture
The Serverless GraphQL Backend ArchitectureThe Serverless GraphQL Backend Architecture
The Serverless GraphQL Backend Architecture
 
MongoDB World 2019: Building a GraphQL API with MongoDB, Prisma, & TypeScript
MongoDB World 2019: Building a GraphQL API with MongoDB, Prisma, & TypeScriptMongoDB World 2019: Building a GraphQL API with MongoDB, Prisma, & TypeScript
MongoDB World 2019: Building a GraphQL API with MongoDB, Prisma, & TypeScript
 
Connecting the Dots: Kong for GraphQL Endpoints
Connecting the Dots: Kong for GraphQL EndpointsConnecting the Dots: Kong for GraphQL Endpoints
Connecting the Dots: Kong for GraphQL Endpoints
 
REST to GraphQL migration: Pros, cons and gotchas
REST to GraphQL migration: Pros, cons and gotchasREST to GraphQL migration: Pros, cons and gotchas
REST to GraphQL migration: Pros, cons and gotchas
 
GraphQL in an Age of REST
GraphQL in an Age of RESTGraphQL in an Age of REST
GraphQL in an Age of REST
 
The Magic of LINE 購物 Testing
The Magic of LINE 購物 TestingThe Magic of LINE 購物 Testing
The Magic of LINE 購物 Testing
 
Better APIs with GraphQL
Better APIs with GraphQL Better APIs with GraphQL
Better APIs with GraphQL
 
Rest vs graphql - why choose
Rest vs graphql - why chooseRest vs graphql - why choose
Rest vs graphql - why choose
 
Diving into GraphQL, React & Apollo
Diving into GraphQL, React & ApolloDiving into GraphQL, React & Apollo
Diving into GraphQL, React & Apollo
 
Tutorial: Building a GraphQL API in PHP
Tutorial: Building a GraphQL API in PHPTutorial: Building a GraphQL API in PHP
Tutorial: Building a GraphQL API in PHP
 
API Technical Writing
API Technical WritingAPI Technical Writing
API Technical Writing
 
Elasticsearch
ElasticsearchElasticsearch
Elasticsearch
 
Using GraphQL for the next generation of the Holdsport APIUsing GraphQL for t...
Using GraphQL for the next generation of the Holdsport APIUsing GraphQL for t...Using GraphQL for the next generation of the Holdsport APIUsing GraphQL for t...
Using GraphQL for the next generation of the Holdsport APIUsing GraphQL for t...
 
MongoDB.local Berlin: Building a GraphQL API with MongoDB, Prisma and Typescript
MongoDB.local Berlin: Building a GraphQL API with MongoDB, Prisma and TypescriptMongoDB.local Berlin: Building a GraphQL API with MongoDB, Prisma and Typescript
MongoDB.local Berlin: Building a GraphQL API with MongoDB, Prisma and Typescript
 
REST API に疲れたあなたへ贈る GraphQL 入門
REST API に疲れたあなたへ贈る GraphQL 入門REST API に疲れたあなたへ贈る GraphQL 入門
REST API に疲れたあなたへ贈る GraphQL 入門
 

More from MarcinStachniuk

[WroclawJUG] Continuous Delivery in OSS using Shipkit
[WroclawJUG] Continuous Delivery in OSS using Shipkit[WroclawJUG] Continuous Delivery in OSS using Shipkit
[WroclawJUG] Continuous Delivery in OSS using Shipkit
MarcinStachniuk
 
Continuous Delivery in OSS using Shipkit.org
Continuous Delivery in OSS using Shipkit.orgContinuous Delivery in OSS using Shipkit.org
Continuous Delivery in OSS using Shipkit.org
MarcinStachniuk
 
Java Web Start – jak żyć z tą dziwną technologią
Java Web Start – jak żyć z tą dziwną technologiąJava Web Start – jak żyć z tą dziwną technologią
Java Web Start – jak żyć z tą dziwną technologią
MarcinStachniuk
 
Zarządzanie zmianami w schemacie relacyjnych baz danych
Zarządzanie zmianami w schemacie relacyjnych baz danychZarządzanie zmianami w schemacie relacyjnych baz danych
Zarządzanie zmianami w schemacie relacyjnych baz danych
MarcinStachniuk
 
Inicjatywa NoSQL na przykładzie db4o
Inicjatywa NoSQL na przykładzie db4oInicjatywa NoSQL na przykładzie db4o
Inicjatywa NoSQL na przykładzie db4o
MarcinStachniuk
 
Automatic mechanism data migration between relational and object database
Automatic mechanism data migration between relational and object databaseAutomatic mechanism data migration between relational and object database
Automatic mechanism data migration between relational and object database
MarcinStachniuk
 
Zastosowanie obiektowych baz danych na przykładzie db4o
Zastosowanie obiektowych baz danych na przykładzie db4oZastosowanie obiektowych baz danych na przykładzie db4o
Zastosowanie obiektowych baz danych na przykładzie db4o
MarcinStachniuk
 
Wprowadzenie do J2ME
Wprowadzenie do J2MEWprowadzenie do J2ME
Wprowadzenie do J2ME
MarcinStachniuk
 
Continuous Delivery w projekcie Open Source - Marcin Stachniuk - DevCrowd 2017
Continuous Delivery w projekcie Open Source - Marcin Stachniuk - DevCrowd 2017Continuous Delivery w projekcie Open Source - Marcin Stachniuk - DevCrowd 2017
Continuous Delivery w projekcie Open Source - Marcin Stachniuk - DevCrowd 2017
MarcinStachniuk
 
Java Web Start czyli jak żyć z tą dziwną technologią? & Continuous Delivery w...
Java Web Start czyli jak żyć z tą dziwną technologią? & Continuous Delivery w...Java Web Start czyli jak żyć z tą dziwną technologią? & Continuous Delivery w...
Java Web Start czyli jak żyć z tą dziwną technologią? & Continuous Delivery w...
MarcinStachniuk
 
Java Web Start czyli jak żyć z tą dziwną technologią & Continuous Delivery w ...
Java Web Start czyli jak żyć z tą dziwną technologią & Continuous Delivery w ...Java Web Start czyli jak żyć z tą dziwną technologią & Continuous Delivery w ...
Java Web Start czyli jak żyć z tą dziwną technologią & Continuous Delivery w ...
MarcinStachniuk
 
Continuous delivery w projekcie open source - Marcin Stachniuk
Continuous delivery w projekcie open source - Marcin StachniukContinuous delivery w projekcie open source - Marcin Stachniuk
Continuous delivery w projekcie open source - Marcin Stachniuk
MarcinStachniuk
 
Zarządzanie zamianami w relacyjnych bazach danych
Zarządzanie zamianami w relacyjnych bazach danychZarządzanie zamianami w relacyjnych bazach danych
Zarządzanie zamianami w relacyjnych bazach danych
MarcinStachniuk
 
Nowości w Javie 8 okiem programisty
Nowości w Javie 8 okiem programistyNowości w Javie 8 okiem programisty
Nowości w Javie 8 okiem programisty
MarcinStachniuk
 
Liquibase - Zarządzanie zmianami w relacyjnych bazach danych
Liquibase - Zarządzanie zmianami w relacyjnych bazach danychLiquibase - Zarządzanie zmianami w relacyjnych bazach danych
Liquibase - Zarządzanie zmianami w relacyjnych bazach danych
MarcinStachniuk
 
Poznaj lepiej swoje srodowisko programistyczne i zwieksz swoja produktywnosc ...
Poznaj lepiej swoje srodowisko programistyczne i zwieksz swoja produktywnosc ...Poznaj lepiej swoje srodowisko programistyczne i zwieksz swoja produktywnosc ...
Poznaj lepiej swoje srodowisko programistyczne i zwieksz swoja produktywnosc ...
MarcinStachniuk
 
Poznaj lepiej swoje srodowisko programistyczne i zwieksz swoja produktywnosc ...
Poznaj lepiej swoje srodowisko programistyczne i zwieksz swoja produktywnosc ...Poznaj lepiej swoje srodowisko programistyczne i zwieksz swoja produktywnosc ...
Poznaj lepiej swoje srodowisko programistyczne i zwieksz swoja produktywnosc ...
MarcinStachniuk
 
Upieksz swoje testy! Testowanie jednostkowe dla sredniozaawansowanych.
Upieksz swoje testy! Testowanie jednostkowe dla sredniozaawansowanych.Upieksz swoje testy! Testowanie jednostkowe dla sredniozaawansowanych.
Upieksz swoje testy! Testowanie jednostkowe dla sredniozaawansowanych.
MarcinStachniuk
 
Podstawy tworzenia gier w J2ME, dla początkujących adeptów sztuki programowania
Podstawy tworzenia gier w J2ME, dla początkujących adeptów sztuki programowaniaPodstawy tworzenia gier w J2ME, dla początkujących adeptów sztuki programowania
Podstawy tworzenia gier w J2ME, dla początkujących adeptów sztuki programowania
MarcinStachniuk
 

More from MarcinStachniuk (19)

[WroclawJUG] Continuous Delivery in OSS using Shipkit
[WroclawJUG] Continuous Delivery in OSS using Shipkit[WroclawJUG] Continuous Delivery in OSS using Shipkit
[WroclawJUG] Continuous Delivery in OSS using Shipkit
 
Continuous Delivery in OSS using Shipkit.org
Continuous Delivery in OSS using Shipkit.orgContinuous Delivery in OSS using Shipkit.org
Continuous Delivery in OSS using Shipkit.org
 
Java Web Start – jak żyć z tą dziwną technologią
Java Web Start – jak żyć z tą dziwną technologiąJava Web Start – jak żyć z tą dziwną technologią
Java Web Start – jak żyć z tą dziwną technologią
 
Zarządzanie zmianami w schemacie relacyjnych baz danych
Zarządzanie zmianami w schemacie relacyjnych baz danychZarządzanie zmianami w schemacie relacyjnych baz danych
Zarządzanie zmianami w schemacie relacyjnych baz danych
 
Inicjatywa NoSQL na przykładzie db4o
Inicjatywa NoSQL na przykładzie db4oInicjatywa NoSQL na przykładzie db4o
Inicjatywa NoSQL na przykładzie db4o
 
Automatic mechanism data migration between relational and object database
Automatic mechanism data migration between relational and object databaseAutomatic mechanism data migration between relational and object database
Automatic mechanism data migration between relational and object database
 
Zastosowanie obiektowych baz danych na przykładzie db4o
Zastosowanie obiektowych baz danych na przykładzie db4oZastosowanie obiektowych baz danych na przykładzie db4o
Zastosowanie obiektowych baz danych na przykładzie db4o
 
Wprowadzenie do J2ME
Wprowadzenie do J2MEWprowadzenie do J2ME
Wprowadzenie do J2ME
 
Continuous Delivery w projekcie Open Source - Marcin Stachniuk - DevCrowd 2017
Continuous Delivery w projekcie Open Source - Marcin Stachniuk - DevCrowd 2017Continuous Delivery w projekcie Open Source - Marcin Stachniuk - DevCrowd 2017
Continuous Delivery w projekcie Open Source - Marcin Stachniuk - DevCrowd 2017
 
Java Web Start czyli jak żyć z tą dziwną technologią? & Continuous Delivery w...
Java Web Start czyli jak żyć z tą dziwną technologią? & Continuous Delivery w...Java Web Start czyli jak żyć z tą dziwną technologią? & Continuous Delivery w...
Java Web Start czyli jak żyć z tą dziwną technologią? & Continuous Delivery w...
 
Java Web Start czyli jak żyć z tą dziwną technologią & Continuous Delivery w ...
Java Web Start czyli jak żyć z tą dziwną technologią & Continuous Delivery w ...Java Web Start czyli jak żyć z tą dziwną technologią & Continuous Delivery w ...
Java Web Start czyli jak żyć z tą dziwną technologią & Continuous Delivery w ...
 
Continuous delivery w projekcie open source - Marcin Stachniuk
Continuous delivery w projekcie open source - Marcin StachniukContinuous delivery w projekcie open source - Marcin Stachniuk
Continuous delivery w projekcie open source - Marcin Stachniuk
 
Zarządzanie zamianami w relacyjnych bazach danych
Zarządzanie zamianami w relacyjnych bazach danychZarządzanie zamianami w relacyjnych bazach danych
Zarządzanie zamianami w relacyjnych bazach danych
 
Nowości w Javie 8 okiem programisty
Nowości w Javie 8 okiem programistyNowości w Javie 8 okiem programisty
Nowości w Javie 8 okiem programisty
 
Liquibase - Zarządzanie zmianami w relacyjnych bazach danych
Liquibase - Zarządzanie zmianami w relacyjnych bazach danychLiquibase - Zarządzanie zmianami w relacyjnych bazach danych
Liquibase - Zarządzanie zmianami w relacyjnych bazach danych
 
Poznaj lepiej swoje srodowisko programistyczne i zwieksz swoja produktywnosc ...
Poznaj lepiej swoje srodowisko programistyczne i zwieksz swoja produktywnosc ...Poznaj lepiej swoje srodowisko programistyczne i zwieksz swoja produktywnosc ...
Poznaj lepiej swoje srodowisko programistyczne i zwieksz swoja produktywnosc ...
 
Poznaj lepiej swoje srodowisko programistyczne i zwieksz swoja produktywnosc ...
Poznaj lepiej swoje srodowisko programistyczne i zwieksz swoja produktywnosc ...Poznaj lepiej swoje srodowisko programistyczne i zwieksz swoja produktywnosc ...
Poznaj lepiej swoje srodowisko programistyczne i zwieksz swoja produktywnosc ...
 
Upieksz swoje testy! Testowanie jednostkowe dla sredniozaawansowanych.
Upieksz swoje testy! Testowanie jednostkowe dla sredniozaawansowanych.Upieksz swoje testy! Testowanie jednostkowe dla sredniozaawansowanych.
Upieksz swoje testy! Testowanie jednostkowe dla sredniozaawansowanych.
 
Podstawy tworzenia gier w J2ME, dla początkujących adeptów sztuki programowania
Podstawy tworzenia gier w J2ME, dla początkujących adeptów sztuki programowaniaPodstawy tworzenia gier w J2ME, dla początkujących adeptów sztuki programowania
Podstawy tworzenia gier w J2ME, dla początkujących adeptów sztuki programowania
 

Recently uploaded

A Comprehensive Look at Generative AI in Retail App Testing.pdf
A Comprehensive Look at Generative AI in Retail App Testing.pdfA Comprehensive Look at Generative AI in Retail App Testing.pdf
A Comprehensive Look at Generative AI in Retail App Testing.pdf
kalichargn70th171
 
Prosigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology SolutionsProsigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology Solutions
Prosigns
 
RISE with SAP and Journey to the Intelligent Enterprise
RISE with SAP and Journey to the Intelligent EnterpriseRISE with SAP and Journey to the Intelligent Enterprise
RISE with SAP and Journey to the Intelligent Enterprise
Srikant77
 
A Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of PassageA Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of Passage
Philip Schwarz
 
Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024
Paco van Beckhoven
 
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Globus
 
May Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdfMay Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdf
Adele Miller
 
Into the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdfInto the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdf
Ortus Solutions, Corp
 
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...
informapgpstrackings
 
How to Position Your Globus Data Portal for Success Ten Good Practices
How to Position Your Globus Data Portal for Success Ten Good PracticesHow to Position Your Globus Data Portal for Success Ten Good Practices
How to Position Your Globus Data Portal for Success Ten Good Practices
Globus
 
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Anthony Dahanne
 
SOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBrokerSOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar
 
Enhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdfEnhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdf
Globus
 
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERRORTROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
Tier1 app
 
Quarkus Hidden and Forbidden Extensions
Quarkus Hidden and Forbidden ExtensionsQuarkus Hidden and Forbidden Extensions
Quarkus Hidden and Forbidden Extensions
Max Andersen
 
AI Pilot Review: The World’s First Virtual Assistant Marketing Suite
AI Pilot Review: The World’s First Virtual Assistant Marketing SuiteAI Pilot Review: The World’s First Virtual Assistant Marketing Suite
AI Pilot Review: The World’s First Virtual Assistant Marketing Suite
Google
 
GlobusWorld 2024 Opening Keynote session
GlobusWorld 2024 Opening Keynote sessionGlobusWorld 2024 Opening Keynote session
GlobusWorld 2024 Opening Keynote session
Globus
 
How Recreation Management Software Can Streamline Your Operations.pptx
How Recreation Management Software Can Streamline Your Operations.pptxHow Recreation Management Software Can Streamline Your Operations.pptx
How Recreation Management Software Can Streamline Your Operations.pptx
wottaspaceseo
 
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, BetterWebinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
XfilesPro
 
Enhancing Project Management Efficiency_ Leveraging AI Tools like ChatGPT.pdf
Enhancing Project Management Efficiency_ Leveraging AI Tools like ChatGPT.pdfEnhancing Project Management Efficiency_ Leveraging AI Tools like ChatGPT.pdf
Enhancing Project Management Efficiency_ Leveraging AI Tools like ChatGPT.pdf
Jay Das
 

Recently uploaded (20)

A Comprehensive Look at Generative AI in Retail App Testing.pdf
A Comprehensive Look at Generative AI in Retail App Testing.pdfA Comprehensive Look at Generative AI in Retail App Testing.pdf
A Comprehensive Look at Generative AI in Retail App Testing.pdf
 
Prosigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology SolutionsProsigns: Transforming Business with Tailored Technology Solutions
Prosigns: Transforming Business with Tailored Technology Solutions
 
RISE with SAP and Journey to the Intelligent Enterprise
RISE with SAP and Journey to the Intelligent EnterpriseRISE with SAP and Journey to the Intelligent Enterprise
RISE with SAP and Journey to the Intelligent Enterprise
 
A Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of PassageA Sighting of filterA in Typelevel Rite of Passage
A Sighting of filterA in Typelevel Rite of Passage
 
Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024
 
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
Innovating Inference - Remote Triggering of Large Language Models on HPC Clus...
 
May Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdfMay Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdf
 
Into the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdfInto the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdf
 
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...
 
How to Position Your Globus Data Portal for Success Ten Good Practices
How to Position Your Globus Data Portal for Success Ten Good PracticesHow to Position Your Globus Data Portal for Success Ten Good Practices
How to Position Your Globus Data Portal for Success Ten Good Practices
 
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
 
SOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBrokerSOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBroker
 
Enhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdfEnhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdf
 
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERRORTROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
 
Quarkus Hidden and Forbidden Extensions
Quarkus Hidden and Forbidden ExtensionsQuarkus Hidden and Forbidden Extensions
Quarkus Hidden and Forbidden Extensions
 
AI Pilot Review: The World’s First Virtual Assistant Marketing Suite
AI Pilot Review: The World’s First Virtual Assistant Marketing SuiteAI Pilot Review: The World’s First Virtual Assistant Marketing Suite
AI Pilot Review: The World’s First Virtual Assistant Marketing Suite
 
GlobusWorld 2024 Opening Keynote session
GlobusWorld 2024 Opening Keynote sessionGlobusWorld 2024 Opening Keynote session
GlobusWorld 2024 Opening Keynote session
 
How Recreation Management Software Can Streamline Your Operations.pptx
How Recreation Management Software Can Streamline Your Operations.pptxHow Recreation Management Software Can Streamline Your Operations.pptx
How Recreation Management Software Can Streamline Your Operations.pptx
 
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, BetterWebinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
Webinar: Salesforce Document Management 2.0 - Smarter, Faster, Better
 
Enhancing Project Management Efficiency_ Leveraging AI Tools like ChatGPT.pdf
Enhancing Project Management Efficiency_ Leveraging AI Tools like ChatGPT.pdfEnhancing Project Management Efficiency_ Leveraging AI Tools like ChatGPT.pdf
Enhancing Project Management Efficiency_ Leveraging AI Tools like ChatGPT.pdf
 

GraphQL - when REST API is to less - lessons learned

  • 1. GraphQL - when REST API is not enough - lessons learned Part 1 Marcin Stachniuk 8 October 2018
  • 3. Agenda 11:00 ● Why? ● Concepts ● Basics 12:00 Lunch 13:00 ● GraphQL in Java ● Lessons learned @MarcinStachniukGraphQL - when REST API is not enough - lessons learned Monady w .NET – i tak używasz, więc dowiedz się, o co chodzi. Mateusz Stasch Rewolucja w analizie danych z RevoscaleR oraz RevoscalePy Tomasz Krawczyk Scale it the easy way - introduction to micro frontends Jakub Holak
  • 4. Who is using REST? @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 5. REST - REpresentational State Transfer https://api.example.com/customers/123 DELETE PUT POST GET PATCH @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 6. REST fixed response GET /customers/111 { "customer": { "id": "111", "name": "John Doe", "email": "john@doe.com", "company": { "id": "222" }, "orders": [ { "id": "333" }, { "id": "444" } ] } } { "customer": { "id": "111", "name": "John Doe", "email": "john@doe.com", "company": { "href": "https://api.example.com/companies/222" }, "orders": [ { "href": "https://api.example.com/orders/333" }, { "href": "https://api.example.com/orders/444" } ] } } RE ST @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 7. REST consequences: several roundtrips @MarcinStachniukGraphQL - when REST API is not enough - lessons learned U nderFetching
  • 8. REST response with nested data GET /customers/111 { "customer": { "id": "111", "name": "John Doe", "email": "john@doe.com", "company": { "id": "222", "name": "My Awesome Corporation", "website": "MyAwesomeCorporation.com" }, "orders": [ { "id": "333", "status": "delivered", "items": [ { "id": "555", "name": "Silver Bullet", "amount": "42", "price": "10000000", "currency": "USD", "producer": { "id": "777", "name": "Lorem Ipsum", "website": "LoremIpsum.com" } } ] }, { "id": "444", "name": "Golden Hammer", "amount": "5", "price": "10000", "currency": "USD", "producer": { ... } } ] } } RE ST @MarcinStachniukGraphQL - when REST API is not enough - lessons learned O verFetching
  • 9. REST response with nested data and limit fields GET /customers/111?fields=name,company/*,orders.status,orders.items(name,producer/name) { "customer": { "id": "111", "name": "John Doe", "email": "john@doe.com", "company": { "id": "222", "name": "My Awesome Corporation", "website": "MyAwesomeCorporation.com" }, "orders": [ { "id": "333", "status": "delivered", "items": [ { "id": "555", "name": "Silver Bullet", "amount": "42", "price": "10000000", "currency": "USD", "producer": { "id": "777", "name": "Lorem Ipsum", "website": "LoremIpsum.com" } } ] }, { "id": "444", "name": "Golden Hammer", "amount": "5", "price": "10000", "currency": "USD", "producer": { ... } } ] } } RE ST @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 10. REST response with projection GET /customers/111?projection=customerPreview { "customer": { "id": "111", "name": "John Doe", "email": "john@doe.com", "company": { "id": "222", "name": "My Awesome Corporation", "website": "MyAwesomeCorporation.com" }, "orders": [ { "id": "333", "status": "delivered", "items": [ { "id": "555", "name": "Silver Bullet", "amount": "42", "price": "10000000", "currency": "USD", "producer": { "id": "777", "name": "Lorem Ipsum", "website": "LoremIpsum.com" } } ] }, { "id": "444", "name": "Golden Hammer", "amount": "5", "price": "10000", "currency": "USD", "producer": { ... } } ] } } RE ST @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 11. Different clients - different needs /web /iphone /android /tv Application Web iPhone Android TV RE ST @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 12. Different clients - different needs /web /iphone /android /tv Application Web iPhone Android TV Content-Type: application/vnd.myawesomecorporation.com+v1+web+json iphone android tv RE ST @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 13. Different clients - different needs /web /iphone /android /tv Application Web iPhone Android TV Content-Type: application/vnd.myawesomecorporation.com+v1+web+json iphone android tv RE ST @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 14. REST contract is rigid @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 15. Platform Architecture Platform App 1 App 2 Customer App X... @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 16. REST API Versioning GET /v2/customers/111RE ST @MarcinStachniukGraphQL - when REST API is not enough - lessons learned GET /customers/111?v=v2RE ST GET /customers/111 Accept header: application/vnd.myapp.2+jsonRE ST GET /customers/111 Custom header: x-ms-version:2RE ST ● How to migrate? ● How to document? ● Is versionless API possible? ● What about continuous evolution of API?
  • 17. Modularisation at UI @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 18. New Frontend Framework ReactJS Relay GraphQL TypeScript @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 19. GraphQL ● Graph Query Language ● Published by Facebook in 2015 ● Growth from Facebook Graph API ● Reference implementation in JavaScript @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 20. GraphQL main concepts ● One endpoint for all operations ● Always define in request what you need ● Queries, Mutations and Subscriptions ● Defined by schema @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 21. Data is a graph @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 22. GraphQL time for demo ● Fragments ● Aliases ● Directives ● Interfaces ● Unions @MarcinStachniukGraphQL - when REST API is not enough - lessons learned ● Query ● Syntax Error ● Mutation ● Operation name ● Variables
  • 23. GraphQL Simple API GET /customers/2?fields=id,name,email type Customer { #fields with ! are not null id: ID! name: String! email: String! } type Query { customer(id: String!): Customer! } { "data": { "customer": { "id": "2", "name": "name", "email": "a@b.com" } } } { customer(id: "2") { id name email } } RE ST @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 24. GraphQL Bad Request GET /custo!@#$ -> 404 { "data": null, "errors": [ { "message": "Invalid Syntax", "locations": [ { "line": 2, "column": 8 } ], "errorType": "InvalidSyntax", "path": null, "extensions": null } ] } { custo!@#$ } RE ST http.cat/200 @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 25. Go back to the roots @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 26. GraphQL Simple API GET /customers/2?fields=id,name,email,company(id,name) type Customer { id: ID! name: String! email: String! company: Company } type Company { id: ID! name: String! website: String! } type Query { customer(id: String!): Customer! } { "data": { "customer": { "id": "2", "name": "name", "email": "a@b.com", "company": { "id": "211", "name": "Company Corp." } } } } { customer(id: "2") { id name email company { id name } } } RE ST @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 27. GraphQL Simple API GET /customers/2?fields=id,name,email,orders(id,status) type Customer { id: ID! name: String! email: String! company: Company orders: [Order] } type Order { id: ID! status: Status } enum Status { NEW, CANCELED, DONE } { "data": { "customer": { "id": "2", "name": "name", "orders": [ { "id": "55", "status": "NEW" }, { "id": "66", "status": "DONE" } ] } } } { customer(id: "2") { id name orders { id status } } } RE ST @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 28. GraphQL mutations input CreateCustomerInput { name: String email: String clientMutationId: String! } type CreateCustomerPayload { customer: Customer clientMutationId: String! } type Mutation { createCustomer(input: CreateCustomerInput): CreateCustomerPayload! } { "data": { "createCustomer": { "customer": { "id": "40", }, "clientMutationId": "123" } } } POST /customers PUT /customers/123 DELETE /customers/123 PATCH /customers/123 mutation { createCustomer(input: { name: "MyName" email: "me@me.com" clientMutationId: "123" }) { customer { id } clientMutationId } } RE ST @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 29. GraphQL mutations + operation name mutation crCust { createCustomer(input: { name: "MyName" email: "me@me.com" clientMutationId: "123" }) { customer { id } clientMutationId } } { "data": { "createCustomer": { "customer": { "id": "40", }, "clientMutationId": "123" } } } POST /customers PUT /customers/123 DELETE /customers/123 PATCH /customers/123RE ST @MarcinStachniukGraphQL - when REST API is not enough - lessons learned mutation { createCustomer(input: { name: "MyName" email: "me@me.com" clientMutationId: "123" }) { customer { id } clientMutationId } }
  • 30. GraphQL Variables { "data": { "createCustomer": { "customer": { "id": "40", }, "clientMutationId": "123" } } } POST /customers PUT /customers/123 DELETE /customers/123 PATCH /customers/123 mutation crCust { createCustomer(input: { name: "MyName" email: "me@me.com" clientMutationId: "123" }) { customer { id } clientMutationId } } RE ST @MarcinStachniukGraphQL - when REST API is not enough - lessons learned mutation crCust ($input: CreateCustInput) { createCustomer(input: $input) { customer { id } clientMutationId } } { "input": { "name": "MyName 2", "email": "me2@me.com", "clientMutationId": "123" } }
  • 31. GraphQL Aliases GET /customers/2?fields=id,name,email + { "data": { "cust1": { "id": "2", "name": "name", "email": "a@b.com" }, "cust2": { "id": "3", "name": "John Doe", "email": "john@doe.com" } } } query get2Cust { cust1: customer(id: "2") { id name email } cust2: customer(id: "3") { id name email } } RE ST @MarcinStachniukGraphQL - when REST API is not enough - lessons learned GET /customers/3?fields=id,name,emailRE ST
  • 32. GraphQL Fragment GET /customers/2?fields=id,name,email + { "data": { "cust1": { "id": "2", "name": "name", "email": "a@b.com" }, "cust2": { "id": "3", "name": "John Doe", "email": "john@doe.com" } } } query get2Cust { cust1: customer(id: "2") { ... frag1 } cust2: customer(id: "3") { ... frag1 } } fragment frag1 on Customer { id name email } RE ST @MarcinStachniukGraphQL - when REST API is not enough - lessons learned GET /customers/3?fields=id,name,emailRE ST
  • 33. GraphQL Directive GET /customers/2?fields=id,name { "data": { "customer": { "id": "2", "name": "name" } } } query getCust ($showEmail: Boolean!) { customer(id: "2") { id name email @include(if: $showEmail) } } { "showEmail": false } RE ST @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 34. GraphQL Interface GET /users?fields=id,name,superAdmin,permissions type Query { users: [User] } interface User { id: ID! name: String! email: String! } type Admin implements User { superAdmin: Boolean! // + id... } type Moderator implements User { permissions: [String] // + id... } { "data": { "users": [ { "id": "777", "name": "Admin a", "superAdmin": true }, { "id": "888", "name": "Moderator", "permissions": [ "Delete Customer", "Delete comment" ]}]}} query getUsers { users { ... on Admin { id name superAdmin } ... on Moderator { id name permissions } } } RE ST @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 35. GraphQL Union GET /search?input=a?fields=typename,name type Query { search(input: String): [SearchResult] } union SearchResult = Customer | Admin | Moderator { "data": { "search": [ { "__typename": "Customer", "name": "name" }, { "__typename": "Admin", "name": "Admin a" }, { "__typename": "Moderator", "name": "Moderator" }]}} query searchSmth { search(input: "a") { __typename ... on Customer { name } ... on Admin { name } ... on Moderator { name } } } RE ST @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 36. Q&A @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 37. Feedback @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 38. To be continued... @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 39. GraphQL - when REST API is not enough - lessons learned Part 2 Marcin Stachniuk 8 October 2018
  • 40. Agenda 11:00 ● Why? ● Concepts ● Basics 12:00 Lunch 13:00 ● GraphQL in Java ● Lessons learned @MarcinStachniukGraphQL - when REST API is not enough - lessons learned Serverless .NET on AWS Wojciech Gawroński Lunch
  • 41. GraphQL ● Graph Query Language ● Published by Facebook in 2015 ● Growth from Facebook Graph API ● Reference implementation in JavaScript ● First version of Java Library: 18 Jul 2015 https://github.com/graphql-java/graphql-java ● First usage: 21 Sep 2015 @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 42. Lessons Learned #1 Never add a library to your project few days after init release @MarcinStachniukGraphQL - when REST API is not enough - lessons learned ● No community ● A lot of bugs ● Bad documentation ● Strict following reference implementation and specification DO NOT TRY THIS AT WORK
  • 43. GraphQL Simple API GET /customers/2?fields=id,name,email,orders(id,status) type Customer { id: ID! name: String! email: String! company: Company orders: [Order] } type Order { id: ID! status: Status } enum Status { NEW, CANCELED, DONE } { "data": { "customer": { "id": "2", "name": "name", "orders": [ { "id": "55", "status": "NEW" }, { "id": "66", "status": "DONE" } ] } } } { customer(id: "2") { id name orders { id status } } } RE ST @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 44. How to implement DataFetcher for queries GET /customers/2?fields=id,name,email,orders(id,status) @Component public class CustomerFetcher extends PropertyDataFetcher<Customer> { @Autowired private CustomerService customerService; @Override public Customer get(DataFetchingEnvironment environment) { String id = environment.getArgument("id"); return customerService.getCustomerById(id); } } RE ST { customer(id: "2") { id name orders { id status } } } @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 45. How to implement DataFetcher for queries GET /customers/2?fields=id,name,email,orders(id,status) public class Customer { private String id; private String name; private String email; // getters are not required } RE ST { customer(id: "2") { id name orders { id status } } } @MarcinStachniukGraphQL - when REST API is not enough - lessons learned public class OrderDataFetcher extends PropertyDataFetcher<List<Order>> { @Override public List<Order> get(DataFetchingEnvironment environment) { Customer source = environment.getSource(); String customerId = source.getId(); return orderService.getOrdersByCustomerId(customerId); } }
  • 46. GraphQL mutations input CreateCustomerInput { name: String email: String clientMutationId: String! } type CreateCustomerPayload { customer: Customer clientMutationId: String! } type Mutation { createCustomer(input: CreateCustomerInput): CreateCustomerPayload! } { "data": { "createCustomer": { "customer": { "id": "40", }, "clientMutationId": "123" } } } POST /customers PUT /customers/123 DELETE /customers/123 PATCH /customers/123 mutation { createCustomer(input: { name: "MyName" email: "me@me.com" clientMutationId: "123" }) { customer { id } clientMutationId } } RE ST @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 47. How to implement DataFetcher for mutations POST /customers PUT /customers/123 DELETE /customers/123 PATCH /customers/123 @Component public class CreateCustomersFetcher extends PropertyDataFetcher<CreateCustomersPayload> { @Override public CreateCustomerPayload get(DataFetchingEnvironment env) { Map<String, Object> input = env.getArgument("input"); String name = (String) input.get("name"); String email = (String) input.get("email"); String clientMutationId = (String) input.get("clientMutationId"); Customer customer = customerService.create(name, email); return new CreateCustomerPayload(customer, clientMutationId); } RE ST mutation { createCustomer(input: { name: "MyName" email: "me@me.com" clientMutationId: "123" }) { customer { id } clientMutationId } } @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 48. In case Interfaces and Unions - Type Resolver is needed public class UserTypeResolver implements TypeResolver { @Override public GraphQLObjectType getType(TypeResolutionEnvironment env) { Object javaObject = env.getObject(); if (javaObject instanceof Admin) { return env.getSchema().getObjectType("Admin"); } else if (javaObject instanceof Moderator) { return env.getSchema().getObjectType("Moderator"); } else { throw new RuntimeException("Unknown type " + javaObject.getClass().getName()); } } } public interface User {...} public class Admin implements User {...} public class Moderator implements User {...} @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 49. Glue everything together RuntimeWiring runtimeWiring = RuntimeWiring.newRuntimeWiring() .type("Query", builder -> builder.dataFetcher("customer", customerFetcher)) .type("Mutation", builder -> builder.dataFetcher("createCustomer", createCustomerFetcher)) .type(newTypeWiring("User") .typeResolver(new UserTypeResolver()) .build()) ... .build(); @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 50. Abstraction over GraphQL Java Our abstraction Data Fetcher 2 Inputs mapping to objects Schema definition Pagination ... Data Fetcher 1 Data Fetcher N... @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 51. Lessons Learned #2 Abstraction is not good if you don’t understand how it works under the hood @MarcinStachniukGraphQL - when REST API is not enough - lessons learned ● Copy paste errors ● Wrong usage ● Hard to update to new version
  • 52. GraphQL type system How to define your schema? @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 53. Code First approach private GraphQLFieldDefinition customerDefinition() { return GraphQLFieldDefinition.newFieldDefinition() .name("customer") .argument(GraphQLArgument.newArgument() .name("id") .type(new GraphQLNonNull(GraphQLString))) .type(new GraphQLNonNull(GraphQLObjectType.newObject() .name("Customer") .field(GraphQLFieldDefinition.newFieldDefinition() .name("id") .description("fields with ! are not null") .type(new GraphQLNonNull(GraphQLID)) .build()) …. .build())) .dataFetcher(customerFetcher) .build(); } Schema First approach type Query { customer(id: String!): Customer! } type Customer { #fields with ! are not null id: ID! name: String! email: String! company: Company orders: [Order] } @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 54. Code First approach - How to build Introspection query Introspection response Replace Relay definitions @MarcinStachniukGraphQL - when REST API is not enough - lessons learned Typescript relay plugin
  • 55. Schema First approach type Customer { # fields with ! are required id: ID! name: String! email: String! company: Company orders: [Order] } *.graphqls SchemaParser schemaParser = new SchemaParser(); File file = // ... TypeDefinitionRegistry registry = schemaParser.parse(file); SchemaGenerator schemaGenerator = new SchemaGenerator(); RuntimeWiring runtimeWiring = RuntimeWiring.newRuntimeWiring() .type("Query", builder -> builder.dataFetcher("customer", customerFetcher)) // ... .build(); return schemaGenerator.makeExecutableSchema(registry, runtimeWiring); @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 56. Schema First approach - project building diagram model.graphqls @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 57. GraphQL SPQR @MarcinStachniukGraphQL - when REST API is not enough - lessons learned https://github.com/leangen/graphql-spqr SPQR - Senatus Populusque Romanus
  • 58. SPQR approach public class UserService { @GraphQLQuery(name = "user") public User getById(@GraphQLArgument(name = "id") Integer id) { //... } } public class Customer { //... @GraphQLQuery(name = "name", description = "A person's name") public String getName() { return name; } } @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 59. Lessons Learned #3 Code First Approach is the worst Schema First Approach: ● Easy to maintain and understand ● Helps organise work ● Demo schema is 3x smaller GraphQL SPQR - ? Code First approach: ● Hard to maintain ● It was the only way at the beginning to define a schema ● No possibility to mix both ● No easy way to migrate to Schema First @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 60. From Code First to Schema First migration https://github.com/mstachniuk/graphql-schema-from-introspection-generator @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 61. GraphQL - How to define pagination, filtering, sorting? Pagination: ● before, after ● offset, limit Filtering: ● filter(name: “Bob” email: “%@gmail.com”) ● filter: { OR: [{ email: “%@gmail.com” }] }, name: “Bob” } Sorting: ● orderBy: ASC, DESC ● sort: NEWEST, IMPORTANCE @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 62. Lessons Learned #4 GraphQL is not full query language @MarcinStachniukGraphQL - when REST API is not enough - lessons learned ● Flexibility ● Less common conventions ● Dgraph.io created GraphQL+-
  • 63. GraphQL downsides @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 64. GraphQL downsides: N+1 problem { customers { 1 call id name orders { n calls id status } } } java-dataloader ● Add async BatchLoader ● Add caching @MarcinStachniukGraphQL - when REST API is not enough - lessons learned graphQL = GraphQL.newGraphQL(schema) .queryExecutionStrategy( new BatchedExecutionStrategy()) .build(); + @Batched in DataFetcher#get()
  • 65. Lessons Learned #5 If you have N + 1 problem use java-dataloader @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 66. Complex Queries fragment TypeRef on __Type { kind name ofType { kind name ofType { kind name ... } } } @MarcinStachniukGraphQL - when REST API is not enough - lessons learned graphQL = GraphQL.newGraphQL(schema) .instrumentation( new ChainedInstrumentation(asList( new MaxQueryComplexityInstrumentation(200), new MaxQueryDepthInstrumentation(20) ))) .build();
  • 67. Lessons Learned #6 Performance killer? Define instrumentation! @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 68. GraphQL downsides: Bad GraphQL API definition - examples { customer(id: "2") { … } customerFull(id: "2") { … } customerFull2(id: "2") { … } customerWithDetails(id: "2") { … } ... } @MarcinStachniukGraphQL - when REST API is not enough - lessons learned { customer(id: "2") { id name orders { id status } } }
  • 69. GraphQL downsides: Bad GraphQL API definition - examples query getUser { user(id: "123") { ... on Admin { id superAdmin } ... on Moderator { id permissions } } } { admin(id: "123") { id superAdmin } moderator(id: "123") { id permissions } } @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 70. GraphQL downsides: Bad GraphQL API definition - examples { orders (input: { status: "NEW" first: "2" offset: "3" }, first: "1", offset: "3") { Items { … } } @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 71. Lessons Learned #7 Thinking shift is a key @MarcinStachniukGraphQL - when REST API is not enough - lessons learned ● Let’s think in graphs and NOT in endpoints / resources / entities / DTOs ● Bad design of our API
  • 72. GraphQL Testing @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 73. Testing GraphQL @SpringBootTest @ContextConfiguration(classes = Main) class CustomerFetcherSpec extends Specification { @Autowired GraphQLSchema graphQLSchema GraphQL graphQL def setup() { graphQL = GraphQL.newGraphQL(graphQLSchema).build() } @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 74. Testing GraphQL def "should get customer by id"() { given: def query = """{ customer(id: "2") { … } }""" def expected = [ "customer": [ … ] ] when: def result = graphQL.execute(query) then: result.data == expected } @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 75. Lessons Learned #8 Testing is easy @MarcinStachniukGraphQL - when REST API is not enough - lessons learned Trap Adventure 2 - "The Hardest Retro Game"
  • 76. Versioning @MarcinStachniukGraphQL - when REST API is not enough - lessons learned GraphQL takes a strong opinion on avoiding versioning by providing the tools for the continuous evolution of a GraphQL schema. Src: https://graphql.org/learn/best-practices/#versioning
  • 77. Versioning type Query { customer(id: String!): Customer! @deprecated(reason: "not used ...") @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 78. Lessons Learned #9 Versioning is not a problem @MarcinStachniukGraphQL - when REST API is not enough - lessons learned GET /v2/customers/111RE ST GET /customers/111?v=v2RE ST GET /customers/111 Accept header: application/vnd.myapp.2+jsonRE ST GET /customers/111 Custom header: x-ms-version:2RE ST Versioning problem is different
  • 79. Tools @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 80. Tools GraphiQL @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 81. Tools Relay @MarcinStachniukGraphQL - when REST API is not enough - lessons learned @MarcinStachniukGraphQL - when REST API is not enough - lessons learned user(...) { photo(width: "120", height: "120") } user(...) { name } user(...) { email } user(...) { name email photo(width: "120", height: "120") }
  • 82. Distelli/graphql-apigen https://github.com/Distelli/graphql-apigen Generate Java APIs with GraphQL Schemas in order to facilitate "schema first" development. @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 83. GraphQL Java Tools https://github.com/graphql-java/graphql-java-tools Map GraphQL schema to POJOs @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 84. More libraries and projects related to graphql-java https://github.com/graphql-java/awesome-graphql-java @MarcinStachniukGraphQL - when REST API is not enough - lessons learned ● Generates a GraphQL schema from a JDBC data source ● Annotations-based syntax for GraphQL schema definition ● JPA Implementation of GraphQL (builds on graphql-java) ● And more examples
  • 85. Apollo @MarcinStachniukGraphQL - when REST API is not enough - lessons learned Build a universal GraphQL API on top of your existing REST APIs, so you can ship new application features fast without waiting on backend changes.
  • 86. Lessons Learned #10 Tooling is nice @MarcinStachniukGraphQL - when REST API is not enough - lessons learned now
  • 87. Summary GraphQL Pros: ● Nice alternative to REST ● It can be used together with REST ● Good integration with Relay / ReactJS ● You get exactly what you want to get ● Good for API with different clients ● Good to use on top of existing API ● Self documented ● Easy testing ● Nice tooling ● Thin layer GraphQL Cons: ● High entry barrier ● Hard to return simple Map ● Not well know (yet) ● Performance overhead ● A lot of similar code to write ● No Operation Idempotency ● No Cache & Security ● No Authorisation ● Always HTTP 200 - unsupported tools @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 88. Nothing is a silver bullet @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 89. Q&A @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 90. Feedback @MarcinStachniukGraphQL - when REST API is not enough - lessons learned
  • 91. GraphQL - when REST API is not enough - lessons learned Part 2 Marcin Stachniuk 8 October 2018 Thank you!