简体   繁体   中英

How to reuse GraphQL individual query API to get the list?

I am trying to get the list of models.

First I have created a model query API. And now I want to get a list by providing ids .

I know I can use Promise.all on getModelById and do some processing to each result I get again.

But is there a way to reuse the individual model query API? Thanks

const ModelType = new GraphQLObjectType({
  name: 'Model',
  fields: {
    id: { type: GraphQLString },
    // ...
  }
});

const RootQuery = new GraphQLObjectType({
  name: 'RootQueryType',
  fields: () => ({
    model: {
      type: ModelType,
      args: {
        id: { type: GraphQLString }
      },
      resolve(parentValue, args) {
        const { id } = args;
        return getModelById(id).then(model => doSomeProcessing(model));
      }
    },

    models: {
      type: new GraphQLList(ModelType),
      args: {
        ids: { type: new GraphQLList(GraphQLString) }
      },
      resolve(parentValue, args) {
        const { ids } = args;
        // here I know I can use Promise.all on getModelById and do my doSomeProcessing again for each result I got,
        // but is there a way to reuse the model query above? Thanks
      }
    }
  })
});

You cannot reference an existing resolver inside another resolver. The only way you can reuse the logic is by abstracting it out into a separate function that gets called by both resolvers. For example:

const getProcessedModelById = (id) => {
  return getModelById(id).then(model => doSomeProcessing(model))
}

// model
resolve(parentValue, args) {
  return getProcessedModelById(args.id)
}

// models
resolve(parentValue, args) {
  return Promise.all(args.ids.map(id => getProcessedModelById(args.id)))
}

Depending on the kind of processing you're doing on the model, it may be possible to do it through field resolvers on the Model type. Let's say your Model type has two fields -- firstName and lastName but your model returns a single field called name . Your doSomeProcessing is just taking that name and breaking it apart into firstName and lastName :

function doSomeProcessing (model) {
  const names = model.name.split(' ')
  return { firstName: names[0], lastName: names[1] }
}

Instead of doing that, your resolvers could just return whatever getModelById returns. Then you can encapsulate the "processing" logic inside each field's resolver:

// firstName field
resolve (parentValue) {
  return parentValue.name.split(' ')[0]
}

// lastName field
resolve (parentValue) {
  return parentValue.name.split(' ')[1]
}

The advantage of this approach is that the "processing" won't actually happen unless that field is requested by the client. In this very simple example, resolving the lastName field is not expensive, but that may not always be the case. It also very neatly encapsulates logic for fields that are derived from the underlying data layer. However, it can also end up being more expensive (imagine, for example, if the split call was itself expensive... now we're calling that method twice instead of once).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM