diff --git a/docs/how-tos/python_consume.md b/docs/how-tos/python_consume.md new file mode 100644 index 0000000..07780a5 --- /dev/null +++ b/docs/how-tos/python_consume.md @@ -0,0 +1,139 @@ +# Consume GraphQL API using Python + +## Preface + +This guide will explain how fetch data from a GraphQL endpoint and map the response to a +Pydantic model. +We will cover: + +- Defining a Pydantic model in [Define the Pydantic Model](#define-the-pydantic-model) +- Fetching the data from GraphQL API in [Fetch Data from GraphQL API](#fetch-data-from-graphql-api) +- Mapping the response to the Pydantic model in [Map Response Pydantic Model](#map-response-to-pydantic-model) + +## Dependencies + +This guide will utilize the following dependencies: + +- `requests` to send HTTP request to the GraphQL endpoint +- `pydantic` for validating and parsing the fetched data + +## Define the Pydantic Model + +Pydantic is a data validation and parsing library in Python. It provides a efficient way to +validate and parse data into Python objects. We can use pydantic models to define the structure and type +of data we intend to fetch from the enpoint. It automatically validates the input data based on +the defined type annotations. If the data does not match the expected types, Pydantic raises errors +ensuring the integrity of the data. + +To defind a Pydantic model, we define a class with Pydantic's `BaseModel` class as the base class. +We can define a `Person` class with the attributes we intend to fetch from the endpoint. + +!!! example "Define Pydantic Model" + + ```python + from pydantic import BaseModel + + class Person(BaseModel): + id: int + first_name: str + last_name: str + + ``` +!!! info + + Refer to the [How to Guide for Python Service docs](https://diamondlightsource.github.io/graph-federation/how-tos/python_service/) to learn more about the GraphQL API structure + +## Fetch Data From GraphQL API + +To fetch data from a GraphQL API, we use the `requests` library to send a POST request with a GraphQL query. +We specify the GraphQL query as a string. + +!!! example "Define Pydantic Model" + + ```python + import requests + + url = 'http://127.0.0.1:8000/graphql' + graphql_query = """ + query { + getPerson { + id, + firstName, + lastName, + } + } + """ + + response = requests.post(url, json={'query': graphql_query}) + + ``` +## Map Response to Pydantic Model + +We can now map the json response we got from the endpoint to a Pydantic model by mapping the response fields to +the Pydantic model fields. + +!!! example "Define Pydantic Model" + + ```python + response_data = response.json() + + # Extract the person data from the response + person_data = response_data['data']['getPerson'] + + # Map the GraphQL response fields to the Pydantic model fields + person = Person( + id=person_data['id'], + first_name=person_data['firstName'], + last_name=person_data['lastName'] + + ``` + +We can define a function `fetch_person` to fetch and map the `Person` data to the Pydantic model. + +!!! example "Fetch and Map Person Data" + + ```python + def fetch_person(): + url = 'http://127.0.0.1:8000/graphql' + query = """ + query { + person { + id, + firstName, + lastName, + } + } + """ + + response = requests.post(url, json={'query': query}) + response_data = response.json() + + person_data = response_data['data']['getPerson'] + + person = Person( + id=person_data['id'], + first_name=person_data['firstName'], + last_name=person_data['lastName'] + ) + return person + + ``` +!!! tip + + Ensure robustness by handling potential validation errors using `pydantic.ValidationError` + +Finally, we can use the function to fetch and print the person data: + +!!! example "Fetch data from GraphQL" + + ```python + if __name__ == "__main__": + person = fetch_person() + if person: + print(person) + ``` + +If the [Python graphQL service](https://diamondlightsource.github.io/graph-federation/how-tos/python_service/) is running, executing +the script should output: + +`id=1 first_name='foo' last_name='bar'`