Search code examples
typescriptgraphqlapollo

How to fetch related objects


For a graph like this:

Company -> (many) Customer -> (many) Invoices Company <-> ASX Record

I have a traditional hierarchy of Companies with customers that receive invoices.

Then I have a table that has today's ASX ranking/market cap etc. The ASX record is assigned the ID of the Company and the Company is assigned the ID of the ASX record.

I thought that when I built resolvers that return all records, I could get details from various objects by running a query like:

query {
  asx {
    CompanyName
    Code
    company {
      id
    }
  }
}

but asx.company comes back as null. That makes sense as company has not been loaded. But I thought Apollo would do some magic based on my typedefs and assemble the reponse as the expected graph of objects and attributes/values:

type asx {
   id : ID!
   Rank : Int
   Code : String
   CompanyName : String
   Price : String
   LastDay : String
   PastWeek : String
   PastMonth : String
   PastYear : String
   Sector : String
   MktCap : String
   company : company
}

type company {
   id : ID!
   asx : asx
   name : String
   code : String
   address : String
}

Is there any simple way to do this? My usecase for this idea is purely to enable prototyping with in-memory database, so there are just arrays of objects behind the resolvers.

Do I have to resolve the relationships myself?


Solution

  • First let's clean up your types a little. GraphQL types don't need to match 1:1 with a relational structure, you have more flexibility. However it's usual practice not to include fields from other types directly in a type but just include the other type as a field (a sort of normal form if you will)

    type ASX {
       id : ID!
       rank : Int
       price : Float
       lastDay : Float
       pastWeek : Float
       pastMonth : Float
       pastYear : Float
       mktCap : Float
       company : Company!
    }
    
    type Company {
       id : ID!
       name : String!
       code : String!
       address : String
       sector : String!
       asx : ASX
    }
    

    Certain GraphQL-centric frameworks (Hasura, AWS Amplify) will resolve foreign table relationships automatically based on a decorated schema definition but vanilla GraphQL does not know how to lookup the related company from the ASX type or how to lookup the related ASX from the company. That's a job for your resolvers.

    In your case you will need to write a resolver for the company field under the ASX type and a resolver for the asx field under the Company type. These should just be simple SQL queries that return a single record.

    For example your company resolver could be:

    company: ({ companyId }) => database('company').where({ id: companyId }).first()
    

    (using knexJS as your ORM)

    You may find my post about GraphQL for SQL developers helpful. It includes many code examples.