Building GraphQL queries with Python

+

=

The problem

The problem

The problem

query {
    bookings (...) {
        edges {
            node {
                startDate
                endDate
                buildingRef
            }
        },
        pageInfo {
            startCursor
            endCursor
        }
    }
}

The problem

query {
    bookings (customerId: "81de7115-b0b2-49ad-ac03-3a56a488ebcd", orderBy: "startDate") {
        edges {
            node {
                startDate
                endDate
                buildingRef
            }
            cursor
        },
        pageInfo {
            startCursor
            endCursor
            hasNextPage
        }
    }
}

The problem

But with Python... 🤷‍♂️

query {
    bookings (customerId: "81de7115-b0b2-49ad-ac03-3a56a488ebcd", orderBy: "startDate") {
        edges {
            node {
                startDate
                endDate
                buildingRef
            }
            cursor
        },
        pageInfo {
            startCursor
            endCursor
            hasNextPage
        }
    }
}

The solution💡

The solution💡

Simple GraphQL Client

The solution💡

Simple GraphQL Client

(the one with most stars on GitHub )

(the most sophisticated one 🧙‍♂️)

sgqlc overview

  • sgqlc.types          - int, str, bool, etc.
  • sgqlc.types.datetime - date, time, datetime
  • sgqlc.types.relay    - Node, Connection
  • sgqlc.operation      - Query (the main entrypoint)
    
  • sgqlc.endpoint.http  - HTTP wrapper

sgqlc overview

  • sgqlc.types
  • sgqlc.types.datetime
    
  • sgqlc.types.relay
  • sgqlc.operation
  • sgqlc.endpoint.http
query {
    bookings (...) {
        edges {
            node {
                startDate
                endDate
                buildingRef
            }
        },
        pageInfo {
            ...
        }
    }
}

Everything is a type, there are just various abstractions throughout the package.

sgqlc overview

  • sgqlc.types
  • sgqlc.types.datetime
  • sgqlc.types.relay
  • sgqlc.operation
    
  • sgqlc.endpoint.http
query {
    bookings (...) {
        edges {
            node {
                startDate
                endDate
                buildingRef
            }
        },
        pageInfo {
            ...
        }
    }
}

sgqlc overview

  • sgqlc.types
  • sgqlc.types.datetime
    
  • sgqlc.types.relay
  • sgqlc.operation
  • sgqlc.endpoint.http
query {
    bookings (...) {
        edges {
            node {
                startDate
                endDate
                buildingRef
            }
        },
        pageInfo {
            ...
        }
    }
}

Relay types are related to pagination, ordering & filtering.

Relay - edges & nodes

Query

edge

edge

edge

Booking

Booking

Booking

node

node

node

cursor

cursor

cursor

sgqlc overview

  • sgqlc.types
  • sgqlc.types.datetime
    
  • sgqlc.types.relay
  • sgqlc.operation
  • sgqlc.endpoint.http
query {
    bookings (...) {
        edges {
            node {
                startDate
                endDate
                buildingRef
            }
        },
        pageInfo {
            ...
        }
    }
}

Relay types are related to pagination, ordering & filtering.

sgqlc overview

  • sgqlc.types
  • sgqlc.types.datetime
  • sgqlc.types.relay
  • sgqlc.operation
    
  • sgqlc.endpoint.http
query {
    bookings (...) {
        edges {
            node {
                startDate
                endDate
                buildingRef
            }
        },
        pageInfo {
            ...
        }
    }
}

Operation == Query (data fetching)

sgqlc overview

  • sgqlc.types
  • sgqlc.types.datetime
  • sgqlc.types.relay
  • sgqlc.operation
    
  • sgqlc.endpoint.http
query {
    bookings (...) {
        edges {
            node {
                startDate
                endDate
                buildingRef
            }
        },
        pageInfo {
            ...
        }
    }
}

Wraps the GraphQL query to a HTTP POST request with the query attached as a body.

Let's define our node

Let's define our node

# schema.py

from sgqlc.types import String
from sgqlc.types.relay import Node
from sgqlc.types.datetime import DateTime


class BookingNode(Node):
    start_date = DateTime
    end_date = DateTime
    building_ref = String

Let's define our node

# schema.py

from sgqlc.types import String
from sgqlc.types.relay import Node
from sgqlc.types.datetime import DateTime


class BookingNode(Node):
    start_date = DateTime
    end_date = DateTime
    building_ref = String
query {
    bookings (...) {
        edges {
            node {
                startDate
                endDate
                buildingRef
            }
            cursor
        },
        ...
    }
}

Let's define our node

# schema.py

from sgqlc.types import String
from sgqlc.types.relay import Node
from sgqlc.types.datetime import DateTime


class BookingNode(Node):
    start_date = DateTime
    end_date = DateTime
    building_ref = String
query {
    bookings (...) {
        edges {
            node {
                startDate
                endDate
                buildingRef
            }
            cursor
        },
        ...
    }
}

The Node model appends the cursor to the node by default.

Let's define our edge

# schema.py

from sgqlc.types import String, Type, Field
from sgqlc.types.relay import Node
from sgqlc.types.datetime import DateTime


class BookingNode(Node):
    start_date = DateTime
    end_date = DateTime
    building_ref = String


class BookingEdge(Type):
    node = Field(BookingNode)
query {
    bookings (...) {
        edges {
            node {
                startDate
                endDate
                buildingRef
            }
            cursor
        },
        ...
    }
}

Let's define our connection

# schema.py

from sgqlc.types import String, Type, Field
from sgqlc.types.relay import Node, Connection
from sgqlc.types.datetime import DateTime


class BookingNode(Node):
    start_date = DateTime
    end_date = DateTime
    building_ref = String


class BookingEdge(Type):
    node = Field(BookingNode)
    

class BookingConnection(Connection):
    edges = list_of(BookingEdge)
query {
    bookings (...) {
        edges {
            node {
                startDate
                endDate
                buildingRef
            }
            cursor
        },
        ...
    }
}

Let's define our connection

# schema.py

from sgqlc.types import String, Type, Field
from sgqlc.types.relay import Node, Connection
from sgqlc.types.datetime import DateTime


class BookingNode(Node):
    start_date = DateTime
    end_date = DateTime
    building_ref = String


class BookingEdge(Type):
    node = Field(BookingNode)
    

class BookingConnection(Connection):
    edges = list_of(BookingEdge)
query {
    bookings (...) {
        edges {
            node {
                startDate
                endDate
                buildingRef
            }
            cursor
        },
        pageInfo {
            startCursor
            endCursor
            hasNextPage
        }
    }
}

The Connection model appends the page info to the query by default.

Let's define our query

# schema.py

from sgqlc.types import String, Type, Field
from sgqlc.types.relay import Node, Connection
from sgqlc.types.datetime import DateTime


class BookingNode(Node):
    start_date = DateTime
    end_date = DateTime
    building_ref = String


class BookingEdge(Type):
    node = Field(BookingNode)
    

class BookingConnection(Connection):
    edges = list_of(BookingEdge)


class Query(Type):
    bookings = Field(
        BookingConnection
    )
query {
    bookings (...) {
        edges {
            node {
                startDate
                endDate
                buildingRef
            }
            cursor
        },
        pageInfo {
            startCursor
            endCursor
            hasNextPage
        }
    }
}

Let's add args to the query

from sgqlc.types import String, Type, Field
from sgqlc.types.relay import Node, Connection
from sgqlc.types.datetime import DateTime


class BookingNode(Node):
    start_date = DateTime
    end_date = DateTime
    building_ref = String


class BookingEdge(Type):
    node = Field(BookingNode)
    

class BookingConnection(Connection):
    edges = list_of(BookingEdge)


class Query(Type):
    bookings = Field(
        BookingConnection,
        args={
          'customer_id': String,
          'order_by': String
        }
    )
query {
    ... (customerId: "", orderBy: "") {
        edges {
            node {
                startDate
                endDate
                buildingRef
            }
            cursor
        },
        pageInfo {
            startCursor
            endCursor
            hasNextPage
        }
    }
}

The schema is done 🏗️

from sgqlc.types import String, Type, Field
from sgqlc.types.relay import Node, Connection
from sgqlc.types.datetime import DateTime


class BookingNode(Node):
    start_date = DateTime
    end_date = DateTime
    building_ref = String


class BookingEdge(Type):
    node = Field(BookingNode)
    

class BookingConnection(Connection):
    edges = list_of(BookingEdge)


class Query(Type):
    bookings = Field(
        BookingConnection,
        args={
          'customer_id': String,
          'order_by': String
        }
    )
query {
    ... (customerId: "", orderBy: "") {
        edges {
            node {
                startDate
                endDate
                buildingRef
            }
            cursor
        },
        pageInfo {
            startCursor
            endCursor
            hasNextPage
        }
    }
}

And last, but not least...

And last, but not least...

Let's build the query !👷

Initialize the query

from sgqlc.operation import Operation
from sgqlc.endpoint.http import HTTPEndpoint

from .schema import Query


bookings_query = Operation(Query)

Provide query filter params

from sgqlc.operation import Operation
from sgqlc.endpoint.http import HTTPEndpoint

from .schema import Query


bookings_query = Operation(Query)

bookings_query.bookings(customer_id='...', order_by='...')

Attach edges & nodes

from sgqlc.operation import Operation
from sgqlc.endpoint.http import HTTPEndpoint

from .schema import Query


bookings_query = Operation(Query)

bookings_query.bookings(customer_id='...', order_by='...')

bookings_query.bookings.edges()                 # Attaches all edges
bookings_query.bookings.edges.node.startDate()  # Attaches only a specific edge

Call a GraphQL endpoint

from sgqlc.operation import Operation
from sgqlc.endpoint.http import HTTPEndpoint

from .schema import Query


bookings_query = Operation(Query)

bookings_query.bookings(customer_id='...', order_by='...')

bookings_query.bookings.edges()                 # Attaches all edges
bookings_query.bookings.edges.node.startDate()  # Attaches only a specific edge

endpoint = HTTPEndpoint(url='https://...')
result = endpoint(query=bookings_query)         # __call__
from sgqlc.operation import Operation
from sgqlc.endpoint.http import HTTPEndpoint

from .schema import Query


bookings_query = Operation(Query)

bookings_query.bookings(customer_id='...', order_by='...')

bookings_query.bookings.edges()                 # Attaches all edges
bookings_query.bookings.edges.node.startDate()  # Attaches only a specific edge

endpoint = HTTPEndpoint(url='https://...')
result = endpoint(query=bookings_query)         # __call__

We got it!🦸‍♂️

But with Python! 🐍

query {
    bookings (customerId: "81de7115-b0b2-49ad-ac03-3a56a488ebcd", orderBy: "startDate") {
        edges {
            node {
                startDate
                endDate
                buildingRef
            }
            cursor
        },
        pageInfo {
            startCursor
            endCursor
            hasNextPage
        }
    }
}

Furthermore

  • first: <number>
  • limit: <number>
    
  • after: <cursor>
  • ...

Q&A 🙋

Building GraphQL queries with Python

By Ventsislav Tashev

Building GraphQL queries with Python

  • 1,892