GraphQL Queries Per App in Django (Graphene)

GraphQL Queries Per App in Django (Graphene)


0

I started moving my REST API endpoints to using GraphQL with Graphene. Seems pretty straightforward so far, but one of the things that I like about the REST API (and I cannot figure out in Graphene) is the structure of "endpoints" for each app. I have a lot of apps in my Django application, and I would like to group the Graphene queries and mutations of each app under a single "endpoint" (just like you would do in REST by sending a request to app_1/endpoint and app_2/endpoint).

Currently I have a graphql folder inside of each app, with files for my queries and mutations inside. Then, under my main schema file, I just create a giant query and mutation objects that inherit from the elements of all other apps.

# app1/graphql/queries.py
class Endpoint1(DjangoObjectType):
    class Meta:
        model = Element1
        fields = ("id", "name", "date")

# app2/graphql/queries.py
class Endpoint2(DjangoObjectType):
    class Meta:
        model = Element2
        fields = ("id", "name", "date")

# Place where my main schema is located
# django_project/graphql/queries.py
class Queries(Endpoint1, Endpoint2):
    pass

Would it be possible to group queries and mutations from a single app and then just inherit from each of the app’s mutations and queries in the main schema, and then have the GraphQL request be structured like this?

query {
  app1 {
    endpoint1 {
      id
      name
    }
  }
}

query {
  app2 {
    endpoint2 {
      id
      name
    }
  }
}

With my current approach I currently just get all of the endpoints bunched up into a single set found under query.

query {
  endpoint1 {
    id
    name
  }
  endpoint2 {
    id
    name
  }
}

7

  • It feels like you are looking for a way to federate your schema. This is something that's often done in javascript based GraphQL servers such as Apollo. Not sure there's a pure Graphene-based approach.

    – Michel Floyd

    Feb 25 at 23:00


  • Man, so is there not any way to simulate it? Or use a special arrangement to get a similar behavior?

    – Eddysanoli

    Feb 26 at 1:15


  • 1

    Gonna answer my own question. Apparently there is a module for graphene called graphene-federation which should solve my problems, but will hold making an official answer until I actually implement it

    – Eddysanoli

    Feb 26 at 22:41

  • @Eddysanoli interested to know your use-case on this. Ideally, Django apps are just a way to encapsulate your code depending on business logic, but I'm not able to understand how having it in your GraphQL query will help.

    – Sanyam Khurana

    Feb 27 at 19:21

  • Hey! @SanyamKhurana, its mainly an organization thing. I have something like 50 models that I want to make available through the GraphQL API, but I dont really like that in the docs that get auto-generated just appear as a giant list. By grouping them the structure will make more sense for future developers (since it follows the same structure for each app) and will be more readable in the docs

    – Eddysanoli

    Feb 27 at 20:30


1 Answer
1


0

So, what I did was not go with federation (as I wanted a simple unified API and federation seemed a bit overkill to me), but to simply split the location of schemas in a per-app basis and simply join them in a common query found in the main Django project folder. Here’s an example:

This is for a file found in django_project/graphql/schema.py

from graphene import ObjectType, Field, Schema
from graphene_federation import key, build_schema

from app_config_generator.graphql.schema import ConfigGeneratorQuery

# ============================================== #
# QUERIES                                        #
# ============================================== #


class Query(ObjectType):
    """
    Queries for all apps in Opus
    """

    # App: Config Generator
    config_generator = Field(
        ConfigGeneratorQuery,
        name="config_generator",
        description="Models for configuration generators"
    )

# ============================================== #
# SCHEMA                                         #
# ============================================== #


schema = Schema(query=Query)

This is then exposed to the browser via this config in django_project/urls.py

from django.urls import path
from graphene_django.views import GraphQLView
from django_project.graphql.schema import schema

# ============================================== #
# BASE ROUTES                                    #
# ============================================== #

urlpatterns = [

    ...

    # GraphQL Routes
    path('graphql/', GraphQLView.as_view(graphiql=True, schema=schema)),

    ...
]

Finally, your app’s schemas should look something like this:

from graphene import ObjectType, List

# Custom Scripts
from app_config_generator.models import (
    SwitchDaylightSavingsModel,
    GPNSVlan
)
from app_config_generator.graphql.fields import (
    GPNSVlanType,
    SwitchDaylightSavingsType
)

# ============================================== #
# SUBQUERIES                                     #
# ============================================== #


class SwitchDaylightSavings(ObjectType):

    switch_daylight_savings = List(
        SwitchDaylightSavingsType,
        description="Pairs all of the available vendors by their daylight savings regions"
    )

    def resolve_switch_daylight_savings(self, info, **kwargs):
        return SwitchDaylightSavingsModel.objects.all()


class GPNSVlans(ObjectType):

    gpns_vlans = List(
        GPNSVlanType,
        description="All VLANs used by the GPNS standard to configure both firewalls and switches."
    )

    def resolve_gpns_vlans(self, info, **kwargs):
        return GPNSVlan.objects.all()


# ============================================== #
# MAIN QUERY                                     #
# ============================================== #

class ConfigGeneratorQuery(
    SwitchDaylightSavings,
    GPNSVlans,
):
    """
    Groups all subqueries for Configuration Generators
    """
    pass

With this I was able to call the "SwitchDaylightSavings" mutation, under the "config_generator" route. I don’t remember the details correctly, but this should give anyone a good head start. I think there are better and more elegant solutions for this, I especially recommend checking out Strawberry



Leave a Reply

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