Agenda
- What is GraphQL? Brief history
- Comparison with REST
-
Sample use cases:
- Cost import
- DecisionsExpanded with ProjectFilter
- Frontend
- Comparison with Redux
- Potential benefits for Antura Projects
GraphQL
Developed at Facebook 2012-2015 as a way to facilitate the company-wide strategy shift to mobile
Extremely fast adoption across the industry after the public release
Solves concrete practical problems, which might explain the growing popularity and fast adoption rates
GraphQL vs REST
GET /api/v1/users
Request
POST /graphql/v1
query {
users {
id
fullName
}
}
GraphQL vs REST
{
users: [
{
id: 1234
fullName: "Glenn Nilsson"
}
]
}
Response
So what? 🤨
REST
Endpoint + Type (Shape)
The shape of data is defined by the endpoint and is static
GET /users/1
{ id, firstName, lastName, login, email, address, ... }
E.g. WBS-Rapport BasicUserInfo
REST
- Many endpoints for different use-cases
- Fetching related data with multiple calls
More code
More traffic
Higher complexity
Problems
GraphQL
Query doesn't enforce response shape
query {
users {
id
firstName
lastName
email
}
}
query {
users {
fullName
login
}
}
GraphQL
Related data in one request
query {
projects {
id
name
sponsor {
fullName
email
}
projectManager {
name
}
}
}
1. api/v1/projects
-> where ProjectNumber == {ProjectNumber}
2. projectId, taskSetId
-> api/v1/projects/{projectId}/tasksets/{taskSetId}/tasks
3. api/v1/propertydefinitions
-> where Name == {TaskReferenceKey}
4. For each taskId:
/api/v1/tasks/{taksId}/propertyvalues/{propertyDefinitionId}
-> where task.StringValue == {TaskReferenceValue}
Cost import via our REST API
Task matching
Task matching with GraphQL
{
tasks(where: {
task_property_values: {
_and: [
{task_property_definition:
{name: {_eq: "IntegrationStandard_TASKREF"}}},
{string_value: {_eq: "01"}}
]}})
{
id
name
task_set {
project {
project_number
name
}
}
task_property_values {
string_value
task_property_definition {
name
}
}
}
}
GraphQL Schema
- Server-side
- Own language - GraphQL SDL
- Describes what data is available
- Describes how to fetch/update data
Schema First
Type system for the API
Types (server-side)
- API return data
- Fields & Relationships
type User {
id: Int!
firstName: String!
}
type Project {
id: Int!
name: String!
projectManager: User!
sponsor: User
}
Queries & Mutations
type Query {
getUsers: [User]
getProjects: [Project]
getUserById(id: Int!): User
}
type Mutation {
deleteUser(id: Int!): User
}
All queries under type Query
All mutations under type Mutation
Mutations
Update project currencyId by projectID
-
REST: PATCH
-
RPC
-
GET + PUT
Mutations
GET /api/v1/projects/{id}
{
"name": "ProjectName",
"projectNumber": "12345",
"deleted": false,
"useResourceRequest": true,
"currencyID": 1,
"lastPublishedTaskSetID": null,
"editTaskSetID": 2,
"latestOfficialTaskSetID": 2,
"projectTypeID": 1,
"phaseIndex": 0,
"sponsorId": 55,
"managerId": 66,
"usePlanning": true,
"canEditAfterFinish": true,
"isTemplateProject": true,
"id": 123
}
REST: Update project currencyId by projectID
PUT /api/v1/projects/{id}
{
"name": "ProjectName",
"projectNumber": "12345",
"deleted": false,
"useResourceRequest": true,
"currencyID": 2,
"lastPublishedTaskSetID": null,
"editTaskSetID": 2,
"latestOfficialTaskSetID": 2,
"projectTypeID": 1,
"phaseIndex": 0,
"sponsorId": 55,
"managerId": 66,
"usePlanning": true,
"canEditAfterFinish": true,
"isTemplateProject": true,
"id": 123
}
Mutations
POST /v1/graphql
mutation {
update_projects(
where: {id: {_eq: 123}},
_set: {currency_id: 2}
)
{
affected_rows
}
}
GraphQL: Update project currencyId by projectID
GraphQL Schema
schema {
query: Query
mutation: Mutation
subscription: Subscription
}
So what?
GraphQL Clients
-
Validation at build time
-
Automatic type generations (e.g. TS)
-
Live documentation (like Swagger)
-
Tooling, intellisense
Download schema definition
GraphiQL
Demo: Hasura, GraphiQL, Insomnia
Introspection query
Client
Introspection query
Schema in json
Query to fetch all schema
Typescript definitions
Demo Frontend
GraphQL Client for React
+ Cache
GraphQL - Frontend
Before
- Types
- Decoder
- ApiCaller
- DataProvider
After
- Types from schema
- Automatic validation
- Call GraphQL API
Manually
GraphQL - Frontend
Apollo cache
-
Components that fetch own data
-
Avoid unnecessary API calls
-
Like redux, but much less code
GraphQL
-
One endpoint
-
Response shape is flexible and defined by the request
-
Smaller payload
-
Strongly typed vs JSON in REST
-
Tooling/discoverability
-
Developer experience
React Views
Redux Store
Single Source of Truth
getState()
dispatch()
subscribe()
Thunks
API
Redux
React Views
Redux Store
Single Source of Truth
getState()
dispatch()
subscribe()
Thunks
API
Connect HoC
Redux
React Views
Server
queries()
mutations()
subscriptions()
Render Props
GraphQL
React Views
Server/DB
Single Source of Truth
queries()
mutations()
subscriptions()
Render Props
GraphQL API
Similar Application Structure to Redux
Much simpler in practice
Potential benefits for AP
- Simpler frontend architecture
- Less traffic between frontend and backend
- Fewer API calls (recent support ticket)
- Integrations: mutations as one operation can potentially allow transactions
Adoption strategies
- (Backend) GraphQL endpoints coexisting with REST
- (Backend) GraphQL layer on top of existing REST endpoints
- (Frontend) GraphQL layer on top of existing REST endpoints
Questions?
G
By margaretkru
G
- 147