jwknz
jwknz

Reputation: 6814

Graphql Interfaces when using MongoDB

I am figuring my way around creating a GraphQL API using MongoDB and I am trying to get my head around interfaces.

I get the idea behind it and watched a bunch of videos on talks and howto's, but the one thing I am seeing is how to make the query resolver.

It is always displayed like this: groups: () => { ... }

groups would be listed in the query type, so it would need the mongodb query.

This is the resolver that I need to find the answer for:

What goes inside of the {...} ?

    Query: {
        groups: () => { ... },
        families: () => Family.find(),
        members: () => Member.find(),
    },

I think the area I am stuck in when it comes to the query is that: "What would the query be since groups is not a mongodb document?"

MORE INFORMATION:

Here is the full typedef

export const typeDefs = gql`

    interface Group {
        id: ID!
        name: String!
    }

    type Family implements Group {
        id: ID!
        name: String! # persons family name
        numberOfPeople: Int
    }

    type Member implements Group {
        id: ID!
        name: String! # persons first name
        age: Int!
    }

    type Query {
        groups: [Group]
        families: [Family]
        members: [Member]
    }
}

Here is the resolver

export const resolvers = {

    Group: {
        __resolveType(group, context, info){
          if(group.family){
            return 'Family';
          }
    
          if(group.member){
            return 'Member';
          }
    
          return null;
        },
      },

    Query: {
        groups: () => { ... },
        families: () => Family.find(),
        members: () => Member.find(),
    }
}

The idea is that Family and Member are separate documents which hold the data and that Group is the interface to create a query that combines them.

Upvotes: 1

Views: 358

Answers (2)

jwknz
jwknz

Reputation: 6814

For anyone who comes to this question - this is the code I had to put inside of the Query{ ... }

Effectively it is the function that executes the database query.

Groups is for a plural return, Group is for a singular return

groups: async () => {

    let types = mongoose.modelNames()

    let total = []

    for(let t of types) {
        let temp = await mongoose.model(t).find()
        total.push(temp)
    }

    let flat = total.flat()

    return flat

},

group: (_, { id }) => {
    
    return mongoose.modelNames().map(async mn => {

        if (await mongoose.model(mn).exists({"_id": ObjectID(id)})) {
            return mongoose.model(mn).findOne({"_id": ObjectID(id)})
        } 

    })

},

Upvotes: 0

PawFV
PawFV

Reputation: 424

edit: I re-readed your post and what you are trying to access here may not exist. Because at the __resolveType you are validating against a schema property.

// Group:
     {
        __resolveType(group, context, info){
          if(group.family){ // property family is not defined in a group implementation.
            return 'Family';
          }
    
          if(group.member){
            return 'Member';
          }
    
          return null;
        },
      },

You may want to perform a validation against a defined unique property from an implementation either Family or Member like follows:

// Group:
     {
        __resolveType(group, context, info){
          if(group.numberOfPeople){
            return 'Family';
          }
    
          if(group.age){
            return 'Member';
          }
    
          return null;
        },
      },

Then when you query groups.

`
{
  groups {
    id
    name
    ... on Family {
      numberOfPeople 
    }
    ... on Member {
      age
    }
  }
}
`

apollo docs reference


Get Automatically generated interfaces and typings.

I have found the best way to get typings for TS automatically from your schema using graphql-code-generator. It has also a plugin to get automatically generated mongoDB models

For a quick response paste your schema here.


Quick setup for typescript:

  1. Install

npm i -D @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-resolvers

It will install cli and typescript + typescript-resolvers plugins.

  1. In your root create codegen.yml and put:
overwrite: true
schema: 'http://localhost:3500/graphql'
generates:
  src/utils/codegen/graphql.ts:
    plugins:
      - 'typescript'
      - 'typescript-resolvers'
  1. excecute command:

graphql-codegen --config codegen.yml --watch src/**/*.ts

  1. Now you can do something as follows:
// Import the types of your generated ts file.
import { MutationResolvers, QueryResolvers, Resolvers } from '@/utils/codegen/graphql'

const Query: QueryResolvers = {
  players: () => players
}

const Mutation: MutationResolvers = {
  updatePlayer: () => player
}

const resolvers: Resolvers = {
  Query,
  Mutation
};
export default resolvers;

Screenshot examples:

intellisense and autocomplete

proper validation

Upvotes: 1

Related Questions