Reputation: 345
I am new using graphql and I would like to improve some features at my API, one of the is get a better filter. This API should return some recipe base on the ingredients that the user will inform in the respective APP, This is The resolver I am using:
module.exports = {
Recipe: {
async ingredients(recipe, _, { dataSources }) {
return await dataSources.IngredientService.getRecipeIngredients(recipe.id)
},
},
Query: {
recipe: async () => db('Recipe'),
ingredient: async () => db('Ingredient'),
recipeByIngredient:async () => db('Recipe'),
}}
the service
class ingredientService {
async getRecipeIngredients(recipe_id) {
const filteredRecipe = db('Ingredient')
.where({ recipe_id })
.join('Recipe', 'Recipe.id', '=', recipe_id)
.select('Recipe.*', 'Ingredient.*')
.whereIn('Ingredient.name', ["sal", "açucar"])
return await filteredRecipe
}
the query schema
type Query {
recipe(name:[String]): [Recipe]
ingredient:[Ingredients]
recipeByIngredient(ingredients:String):[Ingredients]
}
type Recipe {
id: Int
title: String!
author: String
link: String
category: String
subcategory:String
ingredients:[Ingredients]
}
type Ingredients{
id:Int
name:String
quantity:Float
measure:String
observation:String
}
The filter is working but I would like ot improve 2 things:
quer: recipe(name :["sal", "açucar", "farinha"]){ id title author link category subcategory ingredients{ name quantity measure observation } }
but as you can see, the resolver is hardcode, how could I sent the filter to the resolver?
can anyone help me on it? Thanks a lot.
Upvotes: 1
Views: 1269
Reputation: 345
Thank you all that tried to help, all these comments was very important to guide to the final answer. I got one posible solution, that I would like to share and get your feedback, if posible.
On first, I improved my Query resolver
Query: {
recipe(obj, {name}, {dataSources}, info) {
if (name) {
return dataSources.IngredientService.getIngredientsByName(name)
} else {
return db('Recipe')
}
}
Second, I changed my Service to receive the filter
async getIngredientsByName(name) {
const filteredRecipe = db('Ingredient')
//.where({ recipe_id })
.join('Recipe', 'Recipe.id', '=', 'Ingredient.recipe_id')
.select('Recipe.*', 'Ingredient.name', 'Ingredient.quantity', 'Ingredient.measure','Ingredient.observation')
.whereIn('Ingredient.name', name)
return await filteredRecipe
now is everything working fine and making the filter as expected.
Once again, thanks a lot, all of you.
Upvotes: 1
Reputation: 1817
In general, to handle filtering, I set create a Condition
type, named based on context. Here, maybe you'd like to pass a type RecipeCondition
, which defines fields to effectively filter or scope the recipes returned, for example, based on whether it has ingredients in your datastore. This assumes you may want to add additional conditions in future (otherwise, could just hardcode condition in your sql).
type RecipeCondition {
ingredientsRequired: Bool
// Add other condition fields here as needed
...
}
type Query {
recipe(name:[String], condition: RecipeCondition): [Recipe]
...
}
I would handle the filter at the top level where you initially fetch recipes with db service (as opposed to handling in ingredients subresolver). You can simply use this condition, accessible on the recipe resolver arg, and pass it to your db service func that initially fetches a recipes array. If the condition ingredientsRequired
is true
, filter with sql appropriately (will require join to ingredients table and whereIn condition -- if your passing an array of recipe names, this may need to be completed iteratively). In this way, a recipe with no ingredients will not even hit the ingredients subresolver (assuming that condition is desired).
Upvotes: 2