Backend Developer's View on GraphQL

Mafinar Khan

Software Developer, Planswell

In this Talk...

  • History - The Project
  • Backend Workflow Patterns
  • Code Organization Practices

Part I, History - the Project

Vehicle Tracking System

  • Django + React
  • Postgres
  • CouchDB
  • Redis
  • Python (Twisted)

Features

  • Realtime Monitoring
  • Variety of Devices and/or Phone
  • Analytics Reports
  • Hierarchical Authorization System (Three Levels)
  • Timeline
  • Geofence
  • Remote Locking/Engine Control
  • Realtime Image and Video Streaming

Architecture at a Glance

  • Different Devices come with Different Features
  • Bi-directional Communication from web backend to TCP Server
  • Vehicle Data stored in CouchDB
  • Business Information stored in Postgres
  • Message Queue for Image Transfers
  • Redis to store most recent data and Geofence Violations
  • Nearest location query for over 1 million Location Points

Somewhat happy with REST

Until GraphQL Came out...

GraphQL is a query language for your API, and a server-side runtime for executing queries by using a type system you define for your data.

So front-end works like that Postgres Console now?

Initial set of Reactions

  • How can I fit my database there?
  • So `groups/list` is now `groups { ... }`?
  • Why mutation? Why not just use `groups { add() }`
  • Django Models = GraphQL Schema?
  • Where's a DRF equivalent?
  • It doesn't look secured

Week 1: REST == GraphQL

Future us: Noooooooo!

Week 2: GraphQL Types == Django Models

GraphQL

  • Is not REST queried different
  • Is not a fancy collection of ActiveRecord records
  • Queries and Mutations are separate paths
  • Different way of thinking your data
  • Much like database console, only-
    • You design the schema
    • You design the fetching logic
    • You don't care about how the data comes
{
  user {
    id
    vehicles {
        id
        geofence {
           status
           violationTime
        }
        history(from: "2018-01-01") {
          locations {
            id
          }
        }
        lastLocation {
           lat
           lng
           landmark
           speed
        }
        deviceFeatures {
           canSendImage
           canStreamVideo
           canControlEngine
        }
      }
    }
  }
}

            

User Information: Postgres
GeoFence: Redis
Vehicle Last Location: Redis
Photo: File System

History: CouchDB

mutation {
  stopEngine(input: { id: "XX-XX-XXXX" }) {
    vehiclePayload {
      id
      engineStatus
    }
  }
}


mutation {
  takePhoto(input: { id: "XX-XX-XXXX" }) {
    photoPayload {
      data
      timestamp
      message
    } 
}

Sends "stop" signal to the GPS Server that holds device connections

Sends "take photo" signal to the GPS Server that holds device connections, waits for data to be loaded

Thinking in GraphQL

  • The shape of the data you want is of a Graph
  • IDs are important
  • Queries look for data
  • Mutations look for data, expecting modification
    • Make sure to pack inputs
    • Remember the ID
    • Package output in a separate package

Part II, Backend Workflow Patterns

Quick Overview

Here's how it goes

  • Assuming you have everything else ready-
    • Post fullstack meeting: Come up with Schema
    • Implement those Schemas
    • Map schemas with data fetching logic
      • Database query?
      • Calling other REST API?
      • Third party services?
      • Authentication? Authorization?
    • Take care of validation
    • Pack them in the schema data structure

In other words

  • (that one) URLĀ 
  • Schema Design (class? struct? record?)
  • Serialization Technique
  • Pre/Post checks (Middleware?)
  • Resolver Function/Method
  • Domain Logic (Plain old language code)

Be careful about automagic table to schema translators, your usecase and API is yours to design, team work FTW!

Tools! Tools!!

  • You are blessed with GraphiQL, use it while you're in Dev mode
  • Use middleware/dev mode only schemas to know about how the query/mutations impact the system
  • Make middleware (something that intercepts resolver/serialization/dispatch) to know stuff in-transit
  • Make sure to remove them all in production

Part III, Code Organization Practices

File Organization?

  • Have a separate module for GraphQL
  • Hook one (or two for GraphiQL) handler to URL(s)
  • Divide it into two packages
    • Something like `lib`, communicates with database, APIs, does computations etc
    • Serializer module to translate native data-type to GraphQL schema types and vice versa
    • Something like `web` package that includes type definitions, resolvers, queries and mutations

Tips

  • `lib` functions may not know they will be used for GraphQL, they just fetch and mutate data
  • `web` functions should only concern themselves with web related things and completely rely on `lib` functions to get the data and serializers to convert them
  • Resolvers should switch logic path with authentication module calls
  • Each of domain logic, resolvers, queries and mutations should be separately testable
  • Resist the temptation towards automagic unless for simplest cases

The Future

  • Versioning
    • Update the types and resolvers
    • Add to domain logic
  • As long as input/output data shape is the same
    • Fairly easy to switch from ORM calls to SQL, different ORMs, or replacing third-party API calls with homegrown ones
  • Ensure separation of concerns/single responsibility principles among modules
Module (api/) Responsiblity
lib/vehicles/context.py Read/Write logic for all asser related things
utils/vehicles/serializers.py Conversion between GraphQL type to Python native type
web/vehicles/types.py GraphQL Types
web/vehicles/resolvers.py Functions that resolves a path by utilizing lib/asset/*.py functions
web/vehicles/(queries|mutations.py) Root queries and mutations for assets module

Replace .py with .go or .ex if you will

What about the code?

Wait for it...!

You'll really have to wait :(

Thank You.
You guys rock!

Backend Developer's View on GraphQL

By Mafinar Khan

Backend Developer's View on GraphQL

The slides of my talk for GraphQL Toronto Meetup (September 2018) in Shopify. https://www.meetup.com/GraphQL-Toronto/events/254175984/

  • 1,470