Increasing amounts of data are being consumed and generated today. Clients, on one side, need to load data as fast as they can. Developers, on the other side, need to make their apps performant. If your app is fast, your clients will have a better user experience and will be happy, and eventually, your business will make more money.
Modern apps should be faster than the old ones. Your app should get data fast from the server to the client. GraphQL is a sure solution for that.
#Why use GraphQL
Back in 2012, Facebook engineers found that iOS and Android apps frequently crashed. They decided to look at how to improve how Facebook data was being sent to the client apps. Then they built GraphQL for their internal use. In September 2015, Facebook released GraphQL to the public.
In 2000, a Ph.D. dissertation defined REST as a resource-oriented architecture with operations like GET, PUT, POST, and DELETE. Regarding the data model, REST API architecture is much simpler than RPC and SOAP. Countless apps have used REST APIs, however, they have shortcomings, making GraphQL a superior option.
Three major issues REST has:
Over fetching
In the REST world, you get too much data in the response you don't need. This problem is called overfetching. In GraphQL, you're fetching only the fields you want. This makes GraphQL more declarative and faster.
Under fetching
In REST, if you developed an endpoint that returns specific data and there is a feature request to fetch more data from the response, you would need additional requests to get these new data. This is how you underfetched. In GraphQL, you must add new key(s) to the nested query. This will request the data all in just one fetch.
Inflexibility
Another pain of REST APIs is the inflexibility, especially if your app is getting bigger. In REST, when a client needs a change in your app, you will probably create a new endpoint. These endpoints keep adding up whenever there is a need. Thus, more collaboration between your backend and frontend teams. This will cost time and speed, as new endpoints mean more HTTP requests from the clients. In GraphQL, a single endpoint is typically involved. This makes easy organization of data easy and more productivity among your teams.
#Building a simple GraphQL wrapper using Flask
In this post, we will build a simple GraphQL wrapper on top of Hygraph. You'll be able to use the Hygraph GraphQL Query API. We will learn how to authenticate with the Hygraph API using Python, fetch data from the Hygraph server, and wrap the result in a Flask app.
Creating a Hygraph project
Sign up on Hygraph, and please follow this quickstart guide, to create a project, set up a data model, and publish some content to it.
Setting up the Python Flask app
Let us open the terminal and set up a quick virtual environment using the commands below
python -m venv venv# Linuxsource venv/bin/activate# Windowsvenv\Scripts\activatepip install --upgrade pip
We will see three ways to make GraphQL requests with Python:
- Using the
requests
library - Using the
GQL
library. - Using the
graphqlclient
library.
Let us install dependencies, all required dependencies for our project with pip:
pip install flask requests gql graphqlclient
Create a directory structure as shown below
flask_app/│├── app/│ ├── __init__.py│ ├── routes.py│ └── services.py├── run.py├── requirements.txt└── venv/
Add the following code to the respective files
run.py
from app import create_appapp = create_app()if __name__ == '__main__':app.run()
app/__init__.py
from flask import Flaskdef create_app():app = Flask(__name__)# Import routesfrom .routes import main_routesapp.register_blueprint(main_routes)return app
app/routes.py
from flask import Blueprint, jsonifyfrom .services import fetch_data_with_requests, fetch_data_with_gqlmain_routes = Blueprint('main', __name__)@main_routes.route('/get_data_1', methods=['GET'])def get_data_1():data = fetch_data_with_requests()return jsonify(data)@main_routes.route('/get_data_2', methods=['GET'])def get_data_2():data = fetch_data_with_gql()return jsonify(data)@main_routes.route('/get_data_3', methods=['GET'])def get_data_3():data = fetch_data_with_graphqlclient()return jsonify(data)
So far, we have created a very basic Flask application and defined three routes: get_data_1
and get_data_2,
and get_data_3.
These three routes will use the service file to get data from our Hygraph API using different packages and return it to the client. The get_data_1
route is supposed to use the requests
package, while the get_data_2
will use a more structured gql
package to make GraphQL requests, and the get_data_3
route will use the graphqlclient
to make GraphQL requests.
Making GraphQL requests from Python
Let us create our service file and import some fundamental requirements there.
app/services.py
import requestsfrom gql import gql, Clientfrom gql.transport.aiohttp import AIOHTTPTransportfrom graphqlclient import GraphQLClientimport jsonURL = "add_your_hygraph_url_here"TOKEN = "add_your_hygraph_token_here"QUERY = '''query getUsers {products {namepriceimage {urlfileName}}}'''
We have imported the packages that we will require, defined the GraphQL query that we need to make on the GraphQL server, and declared two variables around our hygraph URL
and TOKEN
, do replace them with your own Hygraph URL
and TOKEN
.
Requests
Let us make a GraphQL query using the requests
package. requests
is a general package that can be used to make any HTTP/S requests. For this use case, we need to define headers by providing an authentication bearer token and send a POST
request to the Hygraph server with the query and headers.
import requestsdef fetch_data_with_requests():headers = {"Authorization": f"Bearer {TOKEN}"}response = requests.post(URL, json={'query': QUERY}, headers=headers)return response.json()
GraphQL
On the other hand, gql
is more of a GraphQL-specific client package and is one of the top GraphQL Client libraries available for Python. We need to set up a transport and a client variable as shown below.
transport = AIOHTTPTransport(url=URL, headers={"Authorization": f"Bearer {TOKEN}"})client = Client(transport=transport, fetch_schema_from_transport=True)
Then we can wrap our GraphQL operation using the gql
tag and execute the query.
query = gql(QUERY)result = client.execute(query)
The final code for making a GraphQL request with gql
will look like this
from gql import gql, Clientfrom gql.transport.aiohttp import AIOHTTPTransportdef fetch_data_with_gql():transport = AIOHTTPTransport(url=URL, headers={"Authorization": f"Bearer {TOKEN}"})client = Client(transport=transport, fetch_schema_from_transport=True)query = gql(QUERY)result = client.execute(query)return result
Also, in a proper production app, we only need to define the transport
and client
once when a class initializes, later we can use the same class instance and execute GraphQL operations from anywhere in our application without worrying about connection details.
GraphQLClient
For graphqlclient
, we need to create a client using the GraphQLClient
provided by the library, we can add the Hygraph token using the inject_token
function on the client and pass it the token, finally, we will need to convert the string response to parsable JSON using json.loads
and that’s it.
from graphqlclient import GraphQLClientimport jsondef fetch_data_with_graphqlclient():client = GraphQLClient(URL)client.inject_token(TOKEN)result = json.loads(client.execute(QUERY))return result
Below is the final service file
app/services.py
import requestsfrom gql import gql, Clientfrom gql.transport.aiohttp import AIOHTTPTransportfrom graphqlclient import GraphQLClientimport jsonURL = "add_your_hygraph_url_here"TOKEN = "add_your_hygraph_token_here"QUERY = '''query getUsers {products {namepriceimage {urlfileName}}}def fetch_data_with_requests():headers = {"Authorization": f"Bearer {TOKEN}"}response = requests.post(URL, json={'query': QUERY}, headers=headers)return response.json()def fetch_data_with_gql():transport = AIOHTTPTransport(url=URL, headers={"Authorization": f"Bearer {TOKEN}"})client = Client(transport=transport, fetch_schema_from_transport=True)query = gql(QUERY)result = client.execute(query)return resultdef fetch_data_with_graphqlclient():client = GraphQLClient(URL)client.inject_token(TOKEN)result = json.loads(client.execute(QUERY))return result
#Conclusion
In this article, we went through the problems that GraphQL solves over REST. Through the quickstart, we created data models and published some content in Hygraph and finally, we built a flask wrapper app in Python to query our content via three libraries - requests
, gql,
andgraphqlclient.
Blog Author