Using GraphQL with Strawberry, FastAPI, and Next.js
Tags: graphql, nextjs, webdev
Published: 2022-06-15 17:34:00

**Written by [Yasoob Khalid](https://blog.logrocket.com/author/yasoobkhalid/)✏️**

Hi everyone! 👋 

You've probably heard of FastAPI, Strawberry, GraphQL, and the like. Now, we'll be showing you how to put them together in a Next.js app. We will be focusing on getting a good developer experience (DX) with typed code. Plenty of articles can teach you how to use each individually, but there aren't many resources out there on putting them together, particularly with Strawberry. 

There are multiple Python-based GraphQL libraries and they all vary slightly from each other. For the longest time, [Graphene](https://graphene-python.org/) was a natural choice as it was the oldest and was used in production at different companies, but now other newer libraries have also started gaining some traction. 

We will be focusing on one such library called [Strawberry](https://strawberry.rocks/). It is relatively new and requires Python ≥3.7 because it makes use of Python features that weren't available in earlier versions of the language. It makes heavy use of dataclasses and is fully typed using mypy. 

> **N .B.**, you can find the complete code from this article on [GitHub](https://github.com/yasoob/sqlalchemy-strawberry-fastapi-nextjs).

*   [The final product: A book database](#final-product-book-database)
*   [Getting started](#getting-started)
*   [Strawberry + FastAPI: Hello, world!](#strawberry-fastapi-hello-world)
*   [Defining the schema](#defining-the-schema)
*   [Defining SQLAlchemy models](#defining-sqlalchemy-models)
*   [Defining Strawberry types](#defining-strawberry-types)
*   [Defining queries and mutations](#defining-queries-and-mutations)
*   [Testing out Strawberry](#testing-out-strawberry)
*   [Setting up node dependencies](#setting-up-node-dependencies)
*   [Setting up graphql-codegen](#setting-up-graphql-codegen)
*   [Resolve CORS issue](#resolve-cors-issue)

## The final product: A book database <a name="final-product-book-database">

We will have a basic project structure in place that will demonstrate how you can successfully start writing SQLAlchemy + Strawberry + FastAPI applications while making use of types and automatically generating typed React Hooks to make use of your GraphQL queries and mutations in your Typescript code. The React Hooks will make use of `urql`, but you can easily switch it out for Apollo. 

I will create the DB schema based on the idea of a bookstore. We will store information about authors and their books. We will not create a full application using React/Next.js but will have all the necessary pieces in place to do so if required. 

The goal is to have a better developer experience by using types everywhere and automating as much of the code generation as possible. This will help catch a lot more bugs in development. 

This post is inspired by [this GitHub repo](https://github.com/jokull/python-ts-graphql-demo).

## Getting started

We first need to install the following libraries/packages before we can start working:

*   [Strawberry](https://strawberry.rocks/): this is our GraphQL library that will provide GraphQL support on the Python side
*   [FastAPI](https://fastapi.tiangolo.com/): this is our web framework for serving our Strawberry-based GraphQL API
*   [Uvicorn](https://www.uvicorn.org/): this is an ASGI web server that will serve our FastAPI application in production
*   [Aiosqlite](https://github.com/omnilib/aiosqlite): this provides async support for SQLite
*   [SQLAlchemy](https://www.sqlalchemy.org/): this is our ORM for working with SQLite DB

Let's create a new folder and install these libraries using pip. Instead of creating the new folder manually, I will use the [`create-next-app`](https://nextjs.org/docs/api-reference/create-next-app) command to make it. We will treat the folder created by this command as the root folder for our whole project. This just makes the explanation easier. I will discuss the required JS/TS libraries later on. For now, we will only focus on the Python side. 

Make sure you have `create-next-app` available as a valid command on your system. Once you do, run the following command in the terminal:

```bash
$ npx create-next-app@latest --typescript strawberry_nextjs
```

The above command should create a `strawberry_nextjs` folder. Now go into that folder and install the required Python-based dependencies:

```bash
$ cd strawberry_nextjs

$ python -m venv virtualenv
$ source virtualenv/bin/activate

$ pip install 'strawberry-graphql[fastapi]' fastapi 'uvicorn[standard]' aiosqlite sqlalchemy
```

## Strawberry + FastAPI: Hello, world! <a name="strawberry-fastapi-hello-world">

Let's start with a "Hello, world!" example and it will show us the bits and pieces that make up a Strawberry application. Create a new file named app.py and add the following code to it:

```python
import strawberry

from fastapi import FastAPI
from strawberry.fastapi import GraphQLRouter

authors: list[str] = []

@strawberry.type
class Query:
    @strawberry.field
    def all_authors(self) -> list[str]:
        return authors

@strawberry.type
class Mutation:
    @strawberry.field
    def add_author(self, name: str) -> str:
        authors.append(name)
        return name

schema = strawberry.Schema(query=Query, mutation=Mutation)

graphql_app = GraphQLRouter(schema)

app = FastAPI()
app.include_router(graphql_app, prefix="/graphql")
```

Let's look at this code in chunks. We start by importing the required libraries and packages. We create an authors list that acts as our temporary database and holds the author names (we will create an actual database briefly). 

We then create the Query class and decorate it with the strawberry.type decorator. This converts it into a GraphQL type. Within this class, we define an `all_authors` resolver that returns all the authors from the list. A resolver needs to state its return type as well. We will look at defining slightly complex types in the next section, but for now, a list of strings would suffice. 

Next, we create a new `Mutation` class that contains all the GraphQL mutations. For now, we only have a simple `add_author` mutation that takes in a name and adds it to the authors list. 

Then we pass the query and mutation classes to `strawberry.Schema` to create a GraphQL schema and then pass that on to `GraphQLRouter`. Lastly, we plug in the `GraphQLRouter` to FastAPI and let GraphQLRouter handle all incoming requests to the `/graphql` endpoint. 

If you don't know what these terms mean, then let me give you a quick refresher:

*   Queries: a type of request sent to the server to retrieve data/records
*   [Mutations](https://blog.logrocket.com/supporting-opt-in-nested-mutations-in-graphql/): a type of request sent to the server to create/update/delete data/record
*   Types: the objects we interact with in GraphQL. These represent the data/records/errors and everything in between
*   [Resolver](https://blog.logrocket.com/properly-designed-graphql-resolvers/): a function that populates the data for a single field in our schema

You can read more about the schema basics in Strawberry on the [official docs page](https://strawberry.rocks/docs/general/schema-basics). 

To run this code, hop on over to the terminal and execute the following command:

```bash
$ uvicorn app:app --reload --host '::'
```

This should print something like the following as output:

```
INFO: Will watch for changes in these directories: ['/Users/yasoob/Desktop/strawberry_nextjs']
INFO: Uvicorn running on http://[::]:8000 (Press CTRL+C to quit)
INFO: Started reloader process [56427] using watchgod
INFO: Started server process [56429]
INFO: Waiting for application startup.
INFO: Application startup complete.
```

Now go to [https://127.0.0.1:8000/graphql](https://127.0.0.1:8000/graphql) and you should be greeted by the interactive GraphiQL playground: ![](RackMultipart20220601-1-3iyp32_html_31ae92f13edf1d60.png)![Interactive GraphiQL Playground](https://blog.logrocket.com/wp-content/uploads/2022/06/interactive-graphiql-playground.png) Try executing this query:

```graphql
query MyQuery {
allAuthors
}
```

This should output an empty list. This is expected because we don't have any authors in our list. However, we can fix this by running a mutation first and then running the above query. 

To create a new author, run the `addAuthor` mutation:

```graphql
mutation MyMutation {
addAuthor(name: "Yasoob")
}
```

And now if you run the `allAuthors` query, you should see Yasoob in the output list:

```graphql
{
  "data": {
    "allAuthors": [
      "Yasoob"
    ]
  }
}
```

You might have already realized this by now, but Strawberry automatically converts our camel_case fields into PascalCase fields internally so that we can follow the convention of using PascalCase in our GraphQL API calls and camel_case in our Python code. 

With the basics down, let's go ahead and start working on our bookstore-type application.

## Defining the schema

The very first thing we need to figure out is what our schema is going to be. What queries, mutations, and types do we need to define for our application. 

I will not be focusing on GraphQL basics but rather only on the Strawberry-specific parts in this article. As I already mentioned, we will be following the idea of a bookstore. We will store the data for authors and their books. This is what our database will look like at the end: ![](RackMultipart20220601-1-3iyp32_html_4070ff27e98277f2.png)![Defining Schema](https://blog.logrocket.com/wp-content/uploads/2022/06/defining-schema-1.png)

## Defining SQLAlchemy models

We will be working with SQLAlchemy, so let's define both of our models as classes. We will be using async SQLAlchemy. Create a new `models.py` file in the `strawberry_nextjs` folder and add the following imports to it:

```python
import asyncio
from contextlib import asynccontextmanager
from typing import AsyncGenerator, Optional

from sqlalchemy import Column, ForeignKey, Integer, String
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, sessionmaker
```

These imports will make sense in just a bit. We will be defining our models declaratively using classes that will inherit from the declarative base model from SQLAlchemy. SQLAlchemy provides us with `declarative_base()` function to get the declarative base model. Let's use that and define our models:

```python
Base = declarative_base()

class Author(Base):
    __tablename__ = "authors"
    id: int = Column(Integer, primary_key=True, index=True)
    name: str = Column(String, nullable=False, unique=True)

    books: list["Book"] = relationship("Book", lazy="joined", back_populates="author")

class Book(Base):
    __tablename__ = "books"
    id: int = Column(Integer, primary_key=True, index=True)
    name: str = Column(String, nullable=False)
    author_id: Optional[int] = Column(Integer, ForeignKey(Author.id), nullable=True)

    author: Optional[Author] = relationship(Author, lazy="joined", back_populates="books")
```

`Our Author` class defines two columns: `id` and `name. books` is just a relationship attribute that helps us navigate the relationships between models but is not stored in the authors table as a separate column. We back populate the books attribute as author. This means that we can access `book.author` to access the linked author for a book. 

`The Book` class is very similar to the Author class. We define an additional `author_idcolumn` that links authors and books. This is stored in the book table, unlike the relationships. And we also back populate the `author` attribute as `books`. This way we can access the books of a particular author like this: `author.books`. 

Now we need to tell SQLAlchemy which DB to use and where to find it:

```python
engine = create_async_engine(
    "sqlite+aiosqlite:///./database.db", connect_args={"check_same_thread": False}
)
```

We use `aiosqlite` as part of the connection string as `aiosqlite` allows SQLAlchemy to [use theSQLiteDBin an async manner](https://docs.sqlalchemy.org/en/14/dialects/sqlite.html#aiosqlite). And we pass the `check_same_thread` argument to make sure we can use the same connection across multiple threads. 

It is not safe to use SQLite in a multithreaded fashion without taking extra care to make sure data doesn't get corrupted on concurrent write operations, so it is recommended to use PostgreSQL or a similar high-performance DB in production. 

Next, we need to create a session:

```python
async_session = sessionmaker(
    bind=engine,
    class_=AsyncSession,
    expire_on_commit=False,
    autocommit=False,
    autoflush=False,
)
```

And to make sure we properly close the session on each interaction, we will create a new context manager:

```python
@asynccontextmanager
async def get_session() -> AsyncGenerator[AsyncSession, None]:
    async with async_session() as session:
        async with session.begin():
            try:
                yield session
            finally:
                await session.close()
```

We can use the session without the context manager too, but it will mean that we will have to close the session manually after each session usage. 

Lastly, we need to make sure we have the new DB created. We can add some code to the `models.py` file that will create a new DB file using our declared models if we try to execute the `models.py` file directly:

```python
async def _async_main():
    async with engine.begin() as conn:
        await conn.run_sync(Base.metadata.drop_all)
        await conn.run_sync(Base.metadata.create_all)
    await engine.dispose()

if __name__ == "__main__":
    print("Dropping and re/creating tables")
    asyncio.run(_async_main())
    print("Done.")
```

This will drop all the existing tables in our DB and recreate them based on the models defined in this file. We can add safeguards and make sure we don't delete our data accidentally, but that is beyond the scope of this article. I am just trying to show you how everything ties together. 

Now our `models.py` file is complete and we are ready to define our Strawberry `Author` and `Book` types that will map onto the SQLAlchemy models.

## Defining Strawberry types

By the time you read this article, Strawberry might have stable inbuilt support for directly using SQLAlchemy models, but for now, we have to define custom Strawberry types that will map on to SQLAlchemy models. Let's define those first and then understand how they work. Put this code in the `app.py` file:

```python
import models

# ...

@strawberry.type
class Author:
    id: strawberry.ID
    name: str

    @classmethod
    def marshal(cls, model: models.Author) -> "Author":
        return cls(id=strawberry.ID(str(model.id)), name=model.name)

@strawberry.type
class Book:
    id: strawberry.ID
    name: str
    author: Optional[Author] = None

    @classmethod
    def marshal(cls, model: models.Book) -> "Book":
        return cls(
            id=strawberry.ID(str(model.id)),
            name=model.name,
            author=Author.marshal(model.author) if model.author else None,
        )
```

To define a new type, we simply create a class and decorate it with the strawberry.type decorator. This is very similar to how we defined the `Mutation` and `Query` types. The only difference is that this time, we will not pass these types directly to `strawberry.Schema` so Strawberry won't treat them as `Mutation` or `Query` types. 

Each class has a `marshal` method. This method is what allows us to take in an SQLAlchemy model and create a Strawberry type class instance from it. Strawberry uses `strawberry.ID` to represent a unique identifier to an object. Strawberry provides a few scalar types by default that work just like `strawberry.ID`. It is up to us how we use those to map our SQLAlchemy data to this custom type class attribute. We generally try to find the best and closely resembling alternative to the SQLAlchemy column type and use that. 

In the `Book` class, I also show you how you can mark a type attribute as optional and provide a default value. We mark the author as optional. This is just to show you how it is done and later on; I will mark this as required. 

Another thing to note is that we can also define a list of return types for our mutation and query calls. This makes sure our GraphQL API consumer can process the output appropriately based on the return type it receives. If you know about GraphQL, then this is how we define fragments. Let's first define the types and then I will show you how to use them once we start defining our new mutation and query classes:

```python
@strawberry.type
class AuthorExists:
    message: str = "Author with this name already exists"

@strawberry.type
class AuthorNotFound:
    message: str = "Couldn't find an author with the supplied name"

@strawberry.type
class AuthorNameMissing:
    message: str = "Please supply an author name"

AddBookResponse = strawberry.union("AddBookResponse", (Book, AuthorNotFound, AuthorNameMissing))
AddAuthorResponse = strawberry.union("AddAuthorResponse", (Author, AuthorExists))
```

We are basically saying that our `AddBookResponse` and `AddAuthorResponse` types are union types and can be either of the three (or two) types listed in the tuple.

## Defining queries and mutations

Let's define our queries now. We will have only two queries. One to list all the books and one to list all the authors:

```python
from sqlalchemy import select

# ...

@strawberry.type
class Query:
    @strawberry.field
    async def books(self) -> list[Book]:
        async with models.get_session() as s:
            sql = select(models.Book).order_by(models.Book.name)
            db_books = (await s.execute(sql)).scalars().unique().all()
        return [Book.marshal(book) for book in db_books]

    @strawberry.field
    async def authors(self) -> list[Author]:
        async with models.get_session() as s:
            sql = select(models.Author).order_by(models.Author.name)
            db_authors = (await s.execute(sql)).scalars().unique().all()
        return [Author.marshal(loc) for loc in db_authors]
```

There seems to be a lot happening here, so let's break it down. 

Firstly, look at the books resolver. We use the `get_session` context manager to create a new session. Then we create a new SQL statement that selects Book models and orders them based on the book name. Afterward, we execute the SQL statement using the session we created earlier and put the results in the `db_books` variable. Finally, we marshal each book into a Strawberry Book type and return that as an output. We also mark the return type of books resolver as a `list` of `Books`. 

The `authors` resolver is very similar to the `books` resolver, so I don't need to explain that. 

Let's write our mutations now:

```python
@strawberry.type
class Mutation:
    @strawberry.mutation
    async def add_book(self, name: str, author_name: Optional[str]) -> AddBookResponse:
        async with models.get_session() as s:
            db_author = None
            if author_name:
                sql = select(models.Author).where(models.Author.name == author_name)
                db_author = (await s.execute(sql)).scalars().first()
                if not db_author:
                    return AuthorNotFound()
            else:
                return AuthorNameMissing()
            db_book = models.Book(name=name, author=db_author)
            s.add(db_book)
            await s.commit()
        return Book.marshal(db_book)

    @strawberry.mutation
    async def add_author(self, name: str) -> AddAuthorResponse:
        async with models.get_session() as s:
            sql = select(models.Author).where(models.Author.name == name)
            existing_db_author = (await s.execute(sql)).first()
            if existing_db_author is not None:
                return AuthorExists()
            db_author = models.Author(name=name)
            s.add(db_author)
            await s.commit()
        return Author.marshal(db_author)
```

Mutations are fairly straightforward. Let's start with the `add_book` mutation. 

`add_book` takes in the name of the book and the name of the author as inputs. I am defining the `author_name` as optional just to show you how you can define optional arguments, but in the method body, I enforce the presence of `author_name` by returning `AuthorNameMissing` if the `author_name` is not passed in. 

I filter `Authors` in `db` based on the passed in `author_name` and make sure that an author with the specified name exists. Otherwise, I return `AuthorNotFound`. If both of these checks pass, I create a new `models.Book` instance, add it to the `db` via the session, and commit it. Finally, I return a marshaled book as the return value. 

`add_author` is almost the same as `add_book`, so no reason to go over the code again. 

We are almost done on the Strawberry side, but I have one bonus thing to share, and that is data loaders. 

Another (not always) fun feature of GraphQL is recursive resolvers. You saw above that in the `marshal` method of Book I also define `author`. This way we can run a GraphQL query like this:

```graphql
query {
  book {
    author {
      name
    }
  }
}
```

But what if we want to run a query like this:

```graphql
query {
  author {
    books {
      name
    }
  }
}
```

This will not work because we haven't defined a books attribute on our Strawberry type. Let's rewrite our `Author` class and add a `DataLoader` to the default context Strawberry provides us in our class methods:

```python
from strawberry.dataloader import DataLoader

# ...

@strawberry.type
class Author:
    id: strawberry.ID
    name: str

    @strawberry.field
    async def books(self, info: Info) -> list["Book"]:
        books = await info.context["books_by_author"].load(self.id)
        return [Book.marshal(book) for book in books]

    @classmethod
    def marshal(cls, model: models.Author) -> "Author":
        return cls(id=strawberry.ID(str(model.id)), name=model.name)

# ...

async def load_books_by_author(keys: list) -> list[Book]:
    async with models.get_session() as s:
        all_queries = [select(models.Book).where(models.Book.author_id == key) for key in keys]
        data = [(await s.execute(sql)).scalars().unique().all() for sql in all_queries]
        print(keys, data)
    return data

async def get_context() -> dict:
    return {
        "books_by_author": DataLoader(load_fn=load_books_by_author),
    }

# ...
```

Let's understand this from the bottom up. Strawberry allows us to pass custom functions to our class (those wrapped with `@strawberry.type`) methods via a context. This context is shared across a single request. 

DataLoader allows us to batch multiple requests so that we can reduce back and forth calls to the `db`. We create a `DataLoader` instance and inform it how to load books from the `db` for the passed-in author. We put this `DataLoader` in a dictionary and pass that as the `context_getter` argument to `GraphQLRouter`. This makes the dictionary available to our class methods via `info.context`. We use that to load the books for each author. 

In this example, DataLoader isn't super useful. Its main benefits shine through when we call the `DataLoader` with a list of arguments. That reduces the database calls considerably. And `DataLoaders` also cache output and they are shared in a single request. Therefore, if you were to pass the same arguments to the data loader in a single request multiple times, it will not result in additional database hits. Super powerful!

## Testing out Strawberry

The [uvicorn](https://blog.logrocket.com/building-a-graphql-server-with-fastapi/) instance should automatically reload once you make these code changes and save them. Go over to [http://127.0.0.1:8000/graphql](http://127.0.0.1:8000/graphql) and test out the latest code. 

Try executing the following mutation twice:

```graphql
mutation Author {
  addAuthor(name: "Yasoob") {
    ... on Author {
      id
      name
    }
    ... on AuthorExists{
      message
    }
  }
}
```

The first time it should output this:

```graphql
{
  "data": {
    "addAuthor": {
      "id": "1",
      "name": "Yasoob"
    }
  }
}
```

And the second time it should output this:

```graphql
{
  "data": {
    "addAuthor": {
      "message": "Author with this name already exist"
    }
  }
}
```

![](RackMultipart20220601-1-3iyp32_html_a90b952b537fd83a.png)![Strawberry Output](https://blog.logrocket.com/wp-content/uploads/2022/06/strawberry-output.png) Now let's try adding new books:

```graphql
mutation Book {
  addBook(name: "Practical Python Projects", authorName: "Yasoob") {
    ... on Book {
      id
      name
    }
  }
}
```

![](RackMultipart20220601-1-3iyp32_html_241fc8640aaeb7cd.png)![Python/Strawberry Side](https://blog.logrocket.com/wp-content/uploads/2022/06/python-strawberry-side.png) Sweet! Our Python/Strawberry side is working perfectly fine. But now we need to tie this up on the Node/Next.js side.

## Setting up Node dependencies

We will be using `graphql-codegen` to automatically create typed hooks for us. So the basic workflow will be that before we can use a GraphQL query, mutation, or fragment in our Typescript code, we will define that in a GraphQL file. Then `graphql-codegen` will introspect our Strawberry GraphQL API and create types and use our custom defined GraphQL Query/Mutations/Fragments to create custom `urql` hooks. 

`urql` is a fairly full-featured GraphQL library for React that makes interacting with GraphQL APIs a lot simpler. By doing all this, we will reduce a lot of effort in coding typed hooks ourselves before we can use our GraphQL API in our Next.js app. 

Before we can move on, we need to install a few dependencies:

```bash
$ npm install graphql
$ npm install @graphql-codegen/cli
$ npm install @graphql-codegen/typescript
$ npm install @graphql-codegen/typescript-operations
$ npm install @graphql-codegen/typescript-urql
$ npm install urql
```

Here we are installing `urql` and a few plugins for `@graphql-codegen`.

## Setting up graphql-codegen <a name="setting-up-graphql-codegen">

Now we will create a `codegen.yml` file in the root of our project that will tell `graphql-codegen` what to do:

```yaml
overwrite: true
schema: "http://127.0.0.1:8000/graphql"
documents: './graphql/**/*.graphql'
generates:
  graphql/graphql.ts:
    plugins:
      - "typescript"
      - "typescript-operations"
      - "typescript-urql"
```

We are informing graphql-codegen that it can find the schema for our GraphQL API at [http://127.0.0.1:8000/graphql](http://127.0.0.1:8000/graphql). We also tell it (via the `documents` key) that we have defined our custom fragments, queries, and mutations in graphql files located in the `graphql` folder. Then we instruct it to generate `graphql/graphql.ts` file by running the schema and documents through three plugins. 

Now make a `graphql` folder in our project directory and create a new `operations.graphql` file within it. We will define all the fragments, queries, and mutations we plan on using in our app. We can create separate files for all three and `graphql-codegen` will automatically merge them while processing, but we will keep it simple and put everything in one file for now. Let's add the following GraphQL to `operations.graphql`:

```graphql
query Books {
  books {
    ...BookFields
  }
}

query Authors {
  authors {
    ...AuthorFields
  }
}

fragment BookFields on Book {
  id
  name
  author {
    name
  }
}

fragment AuthorFields on Author {
  id
  name
}

mutation AddBook($name: String!, $authorName: String!) {
  addBook(name: $name, authorName: $authorName) {
      __typename
    ... on Book {
      __typename
      ...BookFields
    }
  }
}

mutation AddAuthor($name: String!) {
  addAuthor(name: $name) {
    __typename
    ... on AuthorExists {
      __typename
      message
    }
    ... on Author {
      __typename
      ...AuthorFields
    }
  }
}
```

This is very similar to the code we were executing in the GraphiQL online interface. This GraphQL code will tell `graphql-codegen` which `urql` mutation and query hooks it needs to produce for us. 

There [has been discussion](https://github.com/dotansimha/graphql-code-generator/discussions/2349) to make `graphql-codegen` generate all mutations and queries by introspecting our online GraphQL API, but so far it is not possible to do that using only `graphql-codegen`. There [do exist tools](https://npm.io/package/gql-typescript-generator) that allow you to do that, but I am not going to use them in this article. You can explore them on your own. 

Let's edit package.json file next and add a command to run `graphql-codegen` via npm. Add this code in the `scripts` section:

```python
"codegen": "graphql-codegen --config codegen.yml"
```

Now we can go to the terminal and run graphql-codegen:

```bash
$ npm run codegen
```

If the command succeeds, you should have a `graphql.ts` file in `graphql` folder. We can go ahead and use the generated `urql` hooks in our Next code like so:

```typescript
import {
  useAuthorsQuery,
} from "../graphql/graphql";

// ....

const [result] = useAuthorsQuery(...);
```

You can read more about the [`graphql-codegen urql` plugin here](https://www.graphql-code-generator.com/plugins/typescript-urql).

## Resolve CORS issue

In a production environment, you can serve the GraphQL API and the Next.js/React app from the same domain+PORT and that will make sure you don't encounter CORS issues. For the development environment, we can add some proxy code to `next.config.js` file to instruct NextJS to proxy all calls to `/graphql` to `uvicorn` that is running on a different port:

```typescript
/** @type {import('next').NextConfig} */
module.exports = {
  reactStrictMode: true,
  async rewrites() {
    return {
      beforeFiles: [
        {
          source: "/graphql",
          destination: "http://localhost:8000/graphql",
        },
      ],
    };
  },
};
```

This will make sure you don't encounter any CORS issues on local development either.

## Conclusion

I hope you learned a thing or two from this article. I deliberately did not go into too much detail on any single topic as such articles already exist online, but it is very hard to find an article that shows you how everything connects together. 

You can find all the code for this article [on my GitHub](https://github.com/yasoob/sqlalchemy-strawberry-fastapi-nextjs). In the future, I might create a full project to show you amore concrete example of how you can make use of the generated code in your apps. In the meantime, you can take a look at [this repo](https://github.com/jokull/python-ts-graphql-demo/), which was inspiration for this article. Jokull was probably the first person to publicly host a project combining all of these different tools. Thanks, Jokull! 

Also, if you have any Python or web development projects in mind, reach out to me at hi@yasoob.me and share your ideas. I do quite a variety of projects so almost nothing is out of the ordinary. Let's create something awesome together. 😄 See you later! 👋 ❤️

---

##Monitor failed and slow GraphQL requests in production

While GraphQL has some features for debugging requests and responses, making sure GraphQL reliably serves resources to your production app is where things get tougher. If you’re interested in ensuring network requests to the backend or third party services are successful, try [LogRocket](https://logrocket.com/signup).

[![LogRocket Mission Control](https://blog.logrocket.com/wp-content/uploads/2017/03/1d0cd-1s_rmyo6nbrasp-xtvbaxfg.png)](https://logrocket.com/signup)

[LogRocket](https://logrocket.com/signup) is like a DVR for web and mobile apps, recording literally everything that happens on your site. Instead of guessing why problems happen, you can aggregate and report on problematic GraphQL requests to quickly understand the root cause. In addition, you can track Apollo client state and inspect GraphQL queries' key-value pairs.

LogRocket instruments your app to record baseline performance timings such as page load time, time to first byte, slow network requests, and also logs Redux, NgRx, and Vuex actions/state. [Start monitoring for free](https://logrocket.com/signup).