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,982