Unlock the Power of FastAPI and GraphQL

Are you tired of building web APIs with tedious boilerplate code? Look no further! FastAPI is a high-performance framework that makes it easy to develop robust web APIs with Python. And when combined with GraphQL, you get a powerful toolset for building flexible and scalable APIs.

Getting Started with FastAPI and GraphQL

Before we dive in, make sure you have Python 3.6+ installed on your machine. You can check by running python --version in your terminal. If you don’t have it, download and install it from the official Python website.

Next, install FastAPI and Uvicorn, an ASGI server, using pip:

pip install fastapi uvicorn

Create a new directory for your app, and inside it, create a new file named main.py. This will be the index file for your server.

GraphQL Basics: Queries and Schema

In GraphQL, queries are used to fetch data, similar to GET requests in REST API architecture. However, with GraphQL queries, you have the flexibility to request exactly what you want. For example, let’s assume you have an API for educational courses. A query to your API might look like this:
graphql
query {
courses {
id
title
instructor
publishDate
}
}

The response would contain courses from your API, along with their properties, in the specified order.

Defining Your GraphQL Schema

The schema describes your GraphQL service, including the data it contains and its format. To demonstrate this, let’s create a schemas.py file in our root directory, which will house all our data fields. We’ll start with the CourseType, which should contain all the information for a particular course.
“`python
import graphene

class CourseType(graphene.ObjectType):
id = graphene.String(required=True)
title = graphene.String(required=True)
instructor = graphene.String(required=True)
publish_date = graphene.DateTime()
“`
Setting Up a Temporary Database

For this demo, we’ll use a JSON database. However, FastAPI supports both relational and non-relational databases like PostgreSQL, MySQL, MongoDB, and ElasticSearch. Create a courses.json file in your root directory and paste the following block of code:
json
[
{
"id": "1",
"title": "Course 1",
"instructor": "John Doe",
"publish_date": "2022-01-01"
},
{
"id": "2",
"title": "Course 2",
"instructor": "Jane Doe",
"publish_date": "2022-02-01"
}
]

Creating Your Query Resolvers

Resolvers are what your GraphQL service will use to interact with your schema and data source. Let’s create a query resolver for fetching courses. In your main.py file, add the following code:
“`python
from fastapi import FastAPI
from graphene import Schema, ObjectType, String, List
from graphql.execution.executors.asyncio import AsyncioExecutor
from starlette.graphql import GraphQLApp

app = FastAPI()

class Query(ObjectType):
get_course = graphene.Field(List(CourseType))

def resolve_get_course(self, info):
    with open('courses.json') as f:
        courses = json.load(f)
    return courses

schema = Schema(query=Query)
“`
Starting Your FastAPI-Powered GraphQL Server

Finally, let’s initialize FastAPI and assign our GraphQL service to the index route. Add the following code to your main.py file:
“`python
@app.route(“/”)
async def graphql_app():
return GraphQLApp(schema)

if name == “main“:
import uvicorn
uvicorn.run(app, host=”0.0.0.0”, port=8000)

Run the following command in your terminal to start your FastAPI app:

uvicorn main:app –host 0.0.0.0 –port 8000

You should see a success message indicating that your app is running. You can now test your GraphQL server by navigating to
http://127.0.0.1:8000` in your browser.

Fetching Data with GraphQL Queries

Let’s explore how to make a query to fetch data from your GraphQL server. In your GraphQL client, paste the following query:
graphql
query {
getCourse {
id
title
instructor
publishDate
}
}

You should receive a response containing the course data.

GraphQL Mutations

We’ve seen how to set up our GraphQL server with FastAPI and fetch data from it. Now, let’s see how we can use GraphQL mutations to add new courses to our data store or update existing courses.

Add the following code to your schemas.py file:
“`python
class CreateCourse(graphene.Mutation):
course = graphene.Field(CourseType)

class Arguments:
    id = graphene.String(required=True)
    title = graphene.String(required=True)
    instructor = graphene.String(required=True)

def mutate(self, info, id, title, instructor):
    with open('courses.json', 'r+') as f:
        courses = json.load(f)
        new_course = {"id": id, "title": title, "instructor": instructor, "publish_date": datetime.now()}
        courses.append(new_course)
        f.seek(0)
        json.dump(courses, f, indent=4)
    return CreateCourse(course=new_course)

class Mutation(graphene.ObjectType):
create_course = CreateCourse.Field()

Add the `Mutation` class to your `schema` definition in your `main.py` file:
python
schema = Schema(query=Query, mutation=Mutation)

Now you can test this by running the following query in your GraphQL client:
graphql
mutation {
createCourse(id: “3”, title: “Course 3”, instructor: “Bob Smith”) {
course {
id
title
instructor
publishDate
}
}
}
“`
You should receive a response containing the newly created course data.

Handling Request Errors

Let’s see how we can handle errors in our app by adding validation for pre-existing IDs. If a user tries to create a course with an ID that already exists in our data store, our GraphQL server should respond with an error message.

Add the following code to your CreateCourse mutation class:
python
def mutate(self, info, id, title, instructor):
with open('courses.json', 'r+') as f:
courses = json.load(f)
for course in courses:
if course['id'] == id:
raise Exception("Course with provided id already exists!")
new_course = {"id": id, "title": title, "instructor": instructor, "publish_date": datetime.now()}
courses.append(new_course)
f.seek(0)
json.dump(courses, f, indent=4)
return CreateCourse(course=new_course)

Now, if you try to create a new course with a pre-existing ID, you should receive an error response.

That’s it! You’ve learned the basics of FastAPI and how to use it to set up a GraphQL server. With these two technologies, you can build robust, high-performance APIs with very little boilerplate code.

Leave a Reply

Your email address will not be published. Required fields are marked *