GraphQL circular queries with one to many relationships

GraphQL circular queries with one to many relationships


1

I’m learning GraphQL by building a simple python application, basically runs nmap scans stores output to a database, and can be queried by a GraphQL API. I seem to be a bit confused on how GraphQL works.

I have a few tables that are one-to-many relationships: user has many scans, scans have results, results have hosts, hosts have ports, hosts have os. Which I defined using sqlalchemy and used graphene

Now, in my GraphQL schema I have:

class Scans(SQLAlchemyObjectType):
    class Meta:
        model = ScansModel


class ScanResult(SQLAlchemyObjectType):
    class Meta:
        model = ScanResultModel


class Hosts(SQLAlchemyObjectType):
    class Meta:
        model = HostInfoModel


class Ports(SQLAlchemyObjectType):
    class Meta:
        model = PortInfoModel


class Os(SQLAlchemyObjectType):
    class Meta:
        model = OsInfoModel

class Query(graphene.ObjectType):
    user = graphene.Field(User)
    scans = graphene.List(Scans)
    scan_results = graphene.List(ScanResult)
    hosts = graphene.List(Hosts)
    ports = graphene.List(Ports)
    os = graphene.Field(Os)

    def resolve_scans(self, info):
        query = Scans.get_query(info)
        return query

Now, when I make a GraphQL query, I can query scans, results, hostinfo, portinfo, osinfo, without having to have resolvers for those fields. I was under the impression that each of those fields would need a resolver.

Furthermore, I seem to be able to do circular queries (so from scanresults I can query scans and from scans I can query user) due to the foreign keys and relationship table.

Is this the correct behaviour, or am misunderstanding how GraphQL works?

Share

2 Answers
2

Reset to default


0

What you need to do is:


class ScanResult(SQLAlchemyObjectType):
    class Meta:
        model = ScanResultModel

    scans = graphene.List(Scans, description="Scans from results.")

    def resolve_scans(self, info):
        query = Scans.get_query(info)
        return query.filter(ScansModel.my_id == self.scans_id).all()

This will probably enables you to build queries like:

{
  scanresult{
    edges {
      node {
         id
         scans{
            id
         }
      }
    }
}

Share


-1

I know that resolvers for each field with SQLAlchemyObjecType are handled inside the library.

when I use mongoengine without using MongoengineObjectType, I code like this.

class Query(graphene.ObjectType):

    department = graphene.List(of_type=DepartmentField,
                           name=graphene.String(default_value="all"))

    role = graphene.List(of_type=RoleField,
                     name=graphene.String(default_value="all"))

    employee = graphene.List(of_type=EmployeeField,
                         name=graphene.String(default_value="all"))

    def resolve_department(self, info, name):
        if name == "all":
            department = [construct(DepartmentField, object) for object in DepartmentModel.objects]
            return department
        else:
            department = DepartmentModel.objects.get(name=name)
            return [construct(DepartmentField, department)]

    def resolve_role(self, info, name):
            .
            .
            .

Share



Not the answer you're looking for? Browse other questions tagged

or ask your own question.

Leave a Reply

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