Coookbooks ========== Explore ingredients ################### Not only can you use simple queries to explore our ingredients database. It is possible to search for specific ingredients, i.e. containing a desired string. Search ingredients ****************** .. code-block:: query search_ingredients{ ingredients(searchName: "appl"){ id name } } .. code-block:: json { "data": { "ingredients": [ { "id": "7", "name": "apple" }, { "id": "9", "name": "apple cider vinegar" }, { "id": "391", "name": "apple cider" }, { "id": "392", "name": "apple juice" }, { "id": "660", "name": "applesauce" }, { "id": "233", "name": "pineapple" }, { "id": "441", "name": "pineapple juice" } ] } } The search works also in multiple languages. Target language can be defined using :ref:`QueryMeta`. .. code-block:: :emphasize-lines: 4 query search_ingredients{ ingredients( searchName: "apf" meta: {language: de} ){ id name } } .. code-block:: json { "data": { "ingredients": [ { "id": "7", "name": "Apfel" }, { "id": "9", "name": "Apfelessig" }, { "id": "391", "name": "Apfelwein" }, { "id": "392", "name": "Apfelsaft" }, { "id": "240", "name": "Granatapfel" }, { "id": "442", "name": "Granatapfelsaft" } ] } } Search by tags ************** In Studio we introduced a versatile concept of :ref:`Tag`. They can be applied for many different objects but let's have a look how to use them with ingredients. First, we can look up all of the tags within category `diet`. .. code-block:: query tags{ tags(category: "diet"){ id name category } } .. code-block:: json { "data": { "tags": [ { "id": "129", "name": "protein", "category": "diet" }, { "id": "130", "name": "gut_health", "category": "diet" }, { "id": "131", "name": "energy", "category": "diet" }, { "id": "132", "name": "immune", "category": "diet" } ] } } For tag-based filtering we can use on of two methods: * `tagAnd` * `tagOr` The former returns objects containing **all** of the tags, whereas the latter, objects containing **at least one** tag. .. code-block:: :emphasize-lines: 2 query ingredient_matches { ingredients(tagsAnd: [130,132]){ id name } } .. code-block:: json { "data": { "ingredients": [ { "id": "2", "name": "agave nectar" }, { "id": "3", "name": "allspice" }, { "id": "4", "name": "almonds" }, { "id": "6", "name": "aniseed" }, { "id": "12", "name": "artichoke" } ] } } Foodpairing suggestions *********************** Getting foodpairing suggestions for a set of ingredients allows to discover sets of ingredients that go well together. It can be looked up using ``matchScore``. .. code-block:: query ingredient_matches { ingredients(matchTo: [17,59,420]){ id name matchScore } } .. code-block:: json { "data": { "ingredients": [ { "id": "1", "name": "acorn squash", "matchScore": 0.0004640691881603378 }, { "id": "2", "name": "agave nectar", "matchScore": 0.02274141704122339 }, { "id": "3", "name": "allspice", "matchScore": 0.00022409417768347553 }, { "id": "4", "name": "almonds", "matchScore": 0.0021007983922955156 }, { "id": "5", "name": "almond milk", "matchScore": 0.0036235160235011466 }, { "id": "6", "name": "aniseed", "matchScore": 7.615664095746823e-05 }, { "id": "7", "name": "apple", "matchScore": 0.00236664036616851 } ] } } To get most out of the foodparing, let's order results by ``matchSchore`` using :ref:``DjangoFilterInput``. Using ``pagination`` we can limit the ordered output to 5 best matching ingredients. .. code-block:: :emphasize-lines: 3 query ingredient_matches { ingredients( matchTo: [17,59,420], djangoFilter: {orderBy: "-match_score"}, pagination: {limitTo: 5}){ id name matchScore } } .. code-block:: json { "data": { "ingredients": [ { "id": "424", "name": "ice", "matchScore": 0.09933129980019301 }, { "id": "425", "name": "lemon juice", "matchScore": 0.07360623298953682 }, { "id": "126", "name": "ginger", "matchScore": 0.04576136137822641 }, { "id": "563", "name": "ground ginger", "matchScore": 0.04576136137822641 }, { "id": "22", "name": "banana", "matchScore": 0.03861570815494316 } ] } } How to get a recipe? #################### Find a dish *********** First, let's find out what dishes there are in studio. .. code-block:: query dishes { dishes { name description } } .. code-block:: json { "data": { "dishes": [ { "id": "91", "name": "Burrito", "description": "Burritos are Tex-Mex traditions - but you can put ANYTHING in them!", "estimatedPreparationTime": 20, "recipeNote": "Don't shy away from adding too many spices and herbs, Mexican cuisine is always spiced!" }, { "id": "241", "name": "Christmas Roasted Veggies", "description": "Create your own roasted veggies for Christmas that can stand alone as a dish or act as the perfect side.", "estimatedPreparationTime": 40, "recipeNote": "Let the oven do the work for you!" }, { "id": "173", "name": "Eggplant Pizza", "description": "Create your very own eggplant pizza and our AI will help you match the rest of the ingredients together.", "estimatedPreparationTime": 30, "recipeNote": "Don't worry if you can't finish your pizza, it will be a perfect snack for lunch the next day!" } ] } Use dish search *************** We can also narrow down our searches using :ref:`DishSearchInput`. For example we can search for mediterranean dishes using roasting methods. We can do so by adding ``keywords`` to ``search`` argument on :ref:`Dish` and ``searchScore`` field. .. code-block:: :emphasize-lines: 2,6 query get_recipe{ dishes(search: {keywords: "mediterranean roasted"}){ id name description searchScore } } .. code-block:: json { "data": { "dishes": [ { "id": "24", "name": "Ovenroasted Mediterranean Veggies", "description": "Mediterrenean ingredients like tomatoes, zucchini or eggplants can gain amazing depth with a bit of roasting.", "searchScore": 1.0 }, { "id": "19", "name": "Mediterranean Savory Muffin", "description": "Yes - you can eat muffins for dinner! Not the sweet kind, but savory muffins with veggies inside", "searchScore": 0.5 }, { "id": "20", "name": "Hummus", "description": "Hummus is a popular Middle Eastern and Mediterranean dip made from mashed chickpeas blended with tahini, olive oil and lemon juice. Jam the rest to make it unique!", "searchScore": 0.5 } ] } Generate a recipe ***************** If we decide which :ref:`Dish` to pick, we can generate a recipe. A recipe consists of different standalone modules: :ref:`Blueprint` and :ref:`Volume`. .. code-block:: query getRecipe { dishes(id: 24) { name serving { name amount } ratio { volumes(ingredients: [28,55,206,167,271]) { ingredient { id name } grams unitCount unit { name } } } blueprint { instructions(ingredients: [28,55,206,167,271]) { text method ingredients { id name } } } } } .. code-block:: json { "data": { "dishes": [ { "name": "Ovenroasted Mediterranean Veggies", "serving": { "name": "Portions", "amount": 1.0 }, "ratio": { "volumes": [ { "ingredient": { "id": "28", "name": "beets" }, "grams": 180, "unitCount": 180.0, "unit": { "name": "grams" } }, { "ingredient": { "id": "55", "name": "carrot" }, "grams": 120, "unitCount": 2.0, "unit": { "name": "pieces" } }, { "ingredient": { "id": "167", "name": "lemon" }, "grams": 15, "unitCount": 1.0, "unit": { "name": "tbsp" } }, { "ingredient": { "id": "206", "name": "olive oil" }, "grams": 20, "unitCount": 25.0, "unit": { "name": "ml" } }, { "ingredient": { "id": "271", "name": "rosemary" }, "grams": 2, "unitCount": 0.5, "unit": { "name": "tsp" } } ] }, "blueprint": { "instructions": [ { "text": "Preheat your oven to 200°C (400°F).", "method": null, "ingredients": [] }, { "text": "Peel and cut the beets and carrot.", "method": "prep", "ingredients": [ { "id": "28", "name": "beets" }, { "id": "55", "name": "carrot" } ] }, { "text": "Cut and squeeze the juice from the lemon.", "method": "prep", "ingredients": [ { "id": "167", "name": "lemon" } ] }, { "text": "Spread the beets evenly on a pan with rosemary and toss with olive oil. Roast at 175°C for 15 minutes. Add carrot and roast for another 30 minutes or until tender.", "method": "roast", "ingredients": [ { "id": "28", "name": "beets" }, { "id": "55", "name": "carrot" }, { "id": "206", "name": "olive oil" }, { "id": "271", "name": "rosemary" } ] }, { "text": "Add salt and pepper to taste.", "method": null, "ingredients": [] }, { "text": "Mix the lemon with a little oil or water.Then drizzle it on top.", "method": "dressing", "ingredients": [ { "id": "167", "name": "lemon" } ] } ] } } ] } } Change recipe language, :ref:`UnitsSystem` and portions ******************************************************* A recipe can be manipulated in many different ways. For instance, it can be presented in a different language using :ref:`Language`, use different set of units by specifying a units system or generate volumes for multiple portions. .. code-block:: :emphasize-lines: 2,9 query getRecipe { dishes(id: 24, meta: {language: da, unitsSystem: IMPERIAL}) { name serving { name amount } ratio { volumes(ingredients: [28,55,206,167,271], portions: 3) { ingredient { id name } grams unitCount unit { name } } } blueprint { instructions(ingredients: [28,55,206,167,271]) { text method ingredients { id name } } } } } .. code-block :: json { "data": { "dishes": [ { "name": "Ovnbagte Middelhavs-grøntsager", "serving": { "name": "Portions", "amount": 1.0 }, "ratio": { "volumes": [ { "ingredient": { "id": "28", "name": "rødbede" }, "grams": 530, "unitCount": 4.0, "unit": { "name": "kop" } }, { "ingredient": { "id": "55", "name": "gulerod" }, "grams": 360, "unitCount": 6.0, "unit": { "name": "stykker" } }, { "ingredient": { "id": "167", "name": "citron" }, "grams": 40, "unitCount": 3.0, "unit": { "name": "spsk." } }, { "ingredient": { "id": "206", "name": "olivenolie" }, "grams": 60, "unitCount": 0.25, "unit": { "name": "kop" } }, { "ingredient": { "id": "271", "name": "rosmarin" }, "grams": 6, "unitCount": 0.5, "unit": { "name": "spsk." } } ] }, "blueprint": { "instructions": [ { "text": "Tænd ovnen på 200°C.", "method": null, "ingredients": [] }, { "text": "Skræl og skær beets and carrot.", "method": "prep", "ingredients": [ { "id": "28", "name": "rødbede" }, { "id": "55", "name": "gulerod" } ] }, { "text": "Skær og pres saften fra lemon.", "method": "prep", "ingredients": [ { "id": "167", "name": "citron" } ] }, { "text": "Spred beets ud på en pande. med rosmarin og tilføj olive oil. Ovnsteg ved 175°C i 15 minutter. Tilføj carrot og ovnsteg igen for 30 minutter eller indtil mørt.", "method": "roast", "ingredients": [ { "id": "28", "name": "rødbede" }, { "id": "55", "name": "gulerod" }, { "id": "206", "name": "olivenolie" }, { "id": "271", "name": "rosmarin" } ] }, { "text": "Smag til med salt og peber.", "method": null, "ingredients": [] }, { "text": "Bland citron med lidt olie eller vand.Fordel det derefter ovenpå.", "method": "dressing", "ingredients": [ { "id": "167", "name": "citron" } ] } ] } } ] } } Ask for substitutions in a dish ******************************* We can check for substitutions of selected ingredients. .. code-block:: :emphasize-lines: 4,8 query getRecipe { dishes(id: 24) { name sub1: substituteIngredient(targetIngredient: 28, contextIngredients: [55,206,167,271]){ id name } sub2: substituteIngredient(targetIngredient: 206, contextIngredients: [28,55,167,271]){ id name } } } .. code-block:: json { "data": { "dishes": [ { "name": "Ovenroasted Mediterranean Veggies", "sub1": [ { "id": "311", "name": "sweet potato" }, { "id": "501", "name": "parsley root" }, { "id": "217", "name": "parsnips" } ], "sub2": [ { "id": "85", "name": "coconut oil" }, { "id": "333", "name": "vegetable oil" }, { "id": "51", "name": "canola oil" }, { "id": "134", "name": "grapeseed oil" } ] } ] } } Balancer ******** The ingredients are what you have in a recipe. Section of taste SWEET says *what can I do if my recipe ended up too sweet*. ``selected`` is what ingredients counter act the sweetness from the ingredients you have and ``suggested`` tells you what else could you add that goes well with your ingredients and also counter acts the sweetness. ``counterTastes`` tells you what tastes will help balance the sweetness out. .. code-block:: query balancer { balancer(ingredients: [28,55,206,167,271]){ section(taste: SWEET){ taste selected{ id name } suggested{ id name } counterTastes } } } .. code-block:: json { "data": { "balancer": { "section": { "taste": "SWEET", "selected": [ { "id": "167", "name": "lemon" }, { "id": "271", "name": "rosemary" } ], "suggested": [ { "id": "6", "name": "aniseed" }, { "id": "9", "name": "apple cider vinegar" }, { "id": "14", "name": "arugula" }, { "id": "20", "name": "balsamic vinegar" } ], "counterTastes": [ "SOUR", "SPICY", "BITTER" ] } } } } Recipe #################### A functional Type *************************** The :ref:`Recipe` can practically be considered a function, or a recipe generator. Given a dish and a set of ingredients, it returns a complete recipe. Being a functional type, ``recipes`` don't have IDs and are not attached to any database model. They are an abstraction of multiple other Types that generally **do** have models. These are a few example use cases. * Retrieve all data returned, to create the initial recipe * Refresh the recipe based on substituted ingredient * Refresh amount of portions .. code-block:: variables: { "dish": 597, "ingredients": [97, 130, 583, 9, 74, 169, 46, 110, 208, 51, 52, 244, 383] } .. code-block:: query recipe($dish: ID!, $ingredients: [ID]!){ recipe(dish: $dish, ingredients: $ingredients){ name description serving{ amount } image{url} dish{ name } instructions{ text } volumes{ grams ingredient{id} } substitutions{ originalIngredient{name} ingredients{name} } } } The returned data is a recipe that we can display to a user, and they will have all the information they need to give it a spin! .. code-block:: json { "data": { "recipe": { "name": "Open-faced Sandwich with Potato", "description": "GRIM and Wasa collaboration recipe", "serving": { "amount": 1 }, "image": { "url": "https://pjstudio-backend-production.s3-eu-central-1.amazonaws.com/images/kartoffelmad.jpg" }, "dish": { "name": "Open-faced Sandwich with Potato" }, "instructions": [ { "text": "Prepare the sauce one day in advance so it has time to cool:" }, { "text": "Roughly grate the gouda cheese." }, { "text": "Mix the apple cider vinegar, eggs, gouda cheese and lemon zest in a blender." }, { "text": "Heat up the cream to a simmer and pour into the blender while running on medium speed. Then turn up to high speed until the mixture is homogenous." }, { "text": "Pour the canola oil in a thin stream into the blender while blending. Continue blending until the sauce has a smooth consistency." }, { "text": "Cool down the sauce - it will thicken as it cools." }, { "text": "Before serving:" }, { "text": "Boil the potato." }, { "text": "Thinly slice the onion." }, { "text": "Coat with white flour." }, { "text": "Fry the canola oil and onion and place on a paper towel to drip off." }, { "text": "Fry off the butter and capers for a few minutes on medium heat to soften and round the flavor." }, { "text": "Add a generous layer of cheese sauce to the crispbread." }, { "text": "Slice the potato and add on top." }, { "text": "Top with capers, chives and onion." } ], "volumes": [ { "grams": 5, "ingredient": { "id": "9" } }, { "grams": 5, "ingredient": { "id": "46" } }, { "grams": 25, "ingredient": { "id": "51" } }, { "grams": 10, "ingredient": { "id": "52" } }, { "grams": 5, "ingredient": { "id": "74" } }, { "grams": 25, "ingredient": { "id": "97" } }, { "grams": 60, "ingredient": { "id": "110" } }, { "grams": 25, "ingredient": { "id": "130" } }, { "grams": 2, "ingredient": { "id": "169" } }, { "grams": 30, "ingredient": { "id": "208" } }, { "grams": 60, "ingredient": { "id": "244" } }, { "grams": 10, "ingredient": { "id": "383" } }, { "grams": 15, "ingredient": { "id": "583" } } ], "substitutions": [ { "originalIngredient": { "id": "9", "name": "apple cider vinegar" }, "ingredients": [ { "id": "167", "name": "lemon" }, { "id": "169", "name": "lemon zest" }, { "id": "174", "name": "lime" }, { "id": "175", "name": "lime zest" }, { "id": "210", "name": "orange zest" }, { "id": "336", "name": "vinegar" } ] }, { "originalIngredient": { "id": "46", "name": "butter" }, "ingredients": [ { "id": "51", "name": "canola oil" }, { "id": "91", "name": "corn oil" }, { "id": "134", "name": "grapeseed oil" }, { "id": "206", "name": "olive oil" }, { "id": "308", "name": "sunflower oil" }, { "id": "333", "name": "vegetable oil" } ] }, { "originalIngredient": { "id": "51", "name": "canola oil" }, "ingredients": [ { "id": "46", "name": "butter" }, { "id": "91", "name": "corn oil" }, { "id": "134", "name": "grapeseed oil" }, { "id": "308", "name": "sunflower oil" }, { "id": "333", "name": "vegetable oil" } ] }, { "originalIngredient": { "id": "74", "name": "chives" }, "ingredients": [ { "id": "107", "name": "dill" }, { "id": "216", "name": "parsley" } ] }, { "originalIngredient": { "id": "97", "name": "cream" }, "ingredients": [ { "id": "208", "name": "onion" }, { "id": "229", "name": "black pepper" }, { "id": "244", "name": "potato" }, { "id": "279", "name": "salt" }, { "id": "383", "name": "white flour" }, { "id": "531", "name": "soy cream" } ] }, { "originalIngredient": { "id": "110", "name": "eggs" }, "ingredients": [ { "id": "525", "name": "egg substitute" }, { "id": "670", "name": "aquafaba" } ] }, { "originalIngredient": { "id": "130", "name": "gouda cheese" }, "ingredients": [ { "id": "120", "name": "fontina cheese" }, { "id": "142", "name": "gruyere cheese" }, { "id": "494", "name": "vegan cheese" }, { "id": "517", "name": "Muenster cheese" } ] }, { "originalIngredient": { "id": "169", "name": "lemon zest" }, "ingredients": [ { "id": "9", "name": "apple cider vinegar" }, { "id": "175", "name": "lime zest" }, { "id": "210", "name": "orange zest" } ] }, { "originalIngredient": { "id": "208", "name": "onion" }, "ingredients": [ { "id": "97", "name": "cream" }, { "id": "261", "name": "red onion" }, { "id": "284", "name": "shallots" } ] }, { "originalIngredient": { "id": "244", "name": "potato" }, "ingredients": [ { "id": "97", "name": "cream" } ] }, { "originalIngredient": { "id": "383", "name": "white flour" }, "ingredients": [ { "id": "97", "name": "cream" }, { "id": "578", "name": "gluten-free flour" } ] } ] } } } Refresh the recipe *************************** With all the recipe data generated, we might want to adapt the recipe by substituting an ingredient. In this case we are substituting the gouda cheese of id **120** with vegan cheese of id **494** .. code-block:: variables: { "dish": 597, "ingredients": [97, 130, 583, 9, 74, 169, 46, 110, 208, 51, 52, 244, 383] "ingredients_substituted": [97, 494, 583, 9, 74, 169, 46, 110, 208, 46, 52, 244, 383] } .. code-block:: query refreshRecipe($dish: ID!, $ingredients_substituted: [ID]!){ recipe(dish: $dish, ingredients: $ingredients_substituted){ instructions{text} volumes{ grams ingredient{id} } substitutions{ originalIngredient{id} ingredients{id} } } } In the response everything has been updated accordingly to our substituted ingredient. .. code-block:: json { "data": { "recipe": { "instructions": [ { "text": "Prepare the sauce one day in advance so it has time to cool:" }, { "text": "Roughly grate the vegan cheese." }, { "text": "Mix the apple cider vinegar, eggs, lemon zest and vegan cheese in a blender." }, { "text": "Heat up the cream to a simmer and pour into the blender while running on medium speed. Then turn up to high speed until the mixture is homogenous." }, { "text": "Cool down the sauce - it will thicken as it cools." }, { "text": "Before serving:" }, { "text": "Boil the potato." }, { "text": "Thinly slice the onion." }, { "text": "Coat with white flour." }, { "text": "Fry the onion and place on a paper towel to drip off." }, { "text": "Fry off the butter and capers for a few minutes on medium heat to soften and round the flavor." }, { "text": "Add a generous layer of cheese sauce to the crispbread." }, { "text": "Slice the potato and add on top." }, { "text": "Top with capers, chives and onion." } ], "volumes": [ { "grams": 5, "ingredient": { "id": "9" } }, { "grams": 5, "ingredient": { "id": "46" } }, { "grams": 10, "ingredient": { "id": "52" } }, { "grams": 5, "ingredient": { "id": "74" } }, { "grams": 30, "ingredient": { "id": "97" } }, { "grams": 60, "ingredient": { "id": "110" } }, { "grams": 2, "ingredient": { "id": "169" } }, { "grams": 30, "ingredient": { "id": "208" } }, { "grams": 70, "ingredient": { "id": "244" } }, { "grams": 10, "ingredient": { "id": "383" } }, { "grams": 30, "ingredient": { "id": "494" } }, { "grams": 15, "ingredient": { "id": "583" } } ], "substitutions": [ { "originalIngredient": { "id": "9", "name": "apple cider vinegar" }, "ingredients": [ { "id": "167", "name": "lemon" }, { "id": "169", "name": "lemon zest" }, { "id": "174", "name": "lime" }, { "id": "175", "name": "lime zest" }, { "id": "210", "name": "orange zest" }, { "id": "336", "name": "vinegar" } ] }, { "originalIngredient": { "id": "46", "name": "butter" }, "ingredients": [ { "id": "51", "name": "canola oil" }, { "id": "91", "name": "corn oil" }, { "id": "134", "name": "grapeseed oil" }, { "id": "206", "name": "olive oil" }, { "id": "308", "name": "sunflower oil" }, { "id": "333", "name": "vegetable oil" } ] }, { "originalIngredient": { "id": "74", "name": "chives" }, "ingredients": [ { "id": "107", "name": "dill" }, { "id": "216", "name": "parsley" } ] }, { "originalIngredient": { "id": "97", "name": "cream" }, "ingredients": [ { "id": "208", "name": "onion" }, { "id": "229", "name": "black pepper" }, { "id": "244", "name": "potato" }, { "id": "279", "name": "salt" }, { "id": "383", "name": "white flour" }, { "id": "531", "name": "soy cream" } ] }, { "originalIngredient": { "id": "110", "name": "eggs" }, "ingredients": [ { "id": "525", "name": "egg substitute" }, { "id": "670", "name": "aquafaba" } ] }, { "originalIngredient": { "id": "169", "name": "lemon zest" }, "ingredients": [ { "id": "9", "name": "apple cider vinegar" }, { "id": "175", "name": "lime zest" }, { "id": "210", "name": "orange zest" } ] }, { "originalIngredient": { "id": "208", "name": "onion" }, "ingredients": [ { "id": "97", "name": "cream" }, { "id": "261", "name": "red onion" }, { "id": "284", "name": "shallots" } ] }, { "originalIngredient": { "id": "244", "name": "potato" }, "ingredients": [ { "id": "97", "name": "cream" } ] }, { "originalIngredient": { "id": "383", "name": "white flour" }, "ingredients": [ { "id": "97", "name": "cream" }, { "id": "578", "name": "gluten-free flour" } ] }, { "originalIngredient": { "id": "494", "name": "vegan cheese" }, "ingredients": [ { "id": "120", "name": "fontina cheese" }, { "id": "130", "name": "gouda cheese" }, { "id": "142", "name": "gruyere cheese" }, { "id": "517", "name": "Muenster cheese" } ] } ] } } } Now we have a recipe where we can substitute ingredients, and refresh the content. We might want an additional refresh query, that specifically changes the amount of portions. What we need to update in this instance, are the volumes. .. code-block:: variables: { "dish": 597, "ingredients": [97, 130, 583, 9, 74, 169, 46, 110, 208, 51, 52, 244, 383], "ingredients_substituted": [97, 494, 583, 9, 74, 169, 46, 110, 208, 46, 52, 244, 383], "portions": 4 } .. code-block:: query refreshPortions($dish: ID, $ingredients_substituted: [ID], $portions: Int){ recipe(dish: $dish, ingredients: $ingredients_substituted){ volumes(portions: $portions){ grams ingredient{id} } } } And in the response we see the IDs of ingredients, and their new measurements in grams, based on 4 portions. .. code-block:: json { "data": { "recipe": { "volumes": [ { "grams": 20, "ingredient": { "id": "9" } }, { "grams": 20, "ingredient": { "id": "46" } }, { "grams": 40, "ingredient": { "id": "52" } }, { "grams": 20, "ingredient": { "id": "74" } }, { "grams": 120, "ingredient": { "id": "97" } }, { "grams": 240, "ingredient": { "id": "110" } }, { "grams": 8, "ingredient": { "id": "169" } }, { "grams": 130, "ingredient": { "id": "208" } }, { "grams": 280, "ingredient": { "id": "244" } }, { "grams": 40, "ingredient": { "id": "383" } }, { "grams": 120, "ingredient": { "id": "494" } }, { "grams": 60, "ingredient": { "id": "583" } } ] } } } These were a few examples of how you can approach using the Recipe Type. Tags ##### Mild Introduction ****************** The :ref:`Tag` is quite universal and powerful for both simple and more advanced filtering. The most important attributes are ``category`` and ``name``. One common category is *dietary* which includes tag names like *vegan*, *nutfree*, *lactosefree* etc. Tag filtering ************** In this example, the task is to figure out which diets you can apply with a dish, and given a set of ingredients. Then, create a recipe based on some suggestions that fit the dietary requirements. Here is our starting point: .. code-block:: variables: { "dish": 171, "ingredients": [17, 22, 163, 97, 43], "category": "dietary" } .. code-block:: query info($dish: ID, $ingredients: [ID]){ dishes(id: $dish){ id name } ingredients(ids: $ingredients){ id name } } .. code-block:: json { "data": { "dishes": [ { "id": "171", "name": "Avocado Banana Kiwi Smoothie" } ], "ingredients": [ { "id": "17", "name": "avocado" }, { "id": "22", "name": "banana" }, { "id": "43", "name": "brown sugar" }, { "id": "97", "name": "cream" }, { "id": "163", "name": "kiwi" } ] } } As a first step, with the *current* ingredients we have, it might be a good idea to get a sense of which dietary requirements they **already** meet. This could easily be its own query, as it is very fast, but in this case we would also like to know which diets are possible with our dish .. code-block:: query dietInfo($dish: ID, $ingredients: [ID], $category: String){ tags(shared: {type: INGREDIENT, ids: $ingredients}, category: $category){ id name } dishes(id: $dish){ id name adaptableToTags(category: $category){ id name } } } Now we know that with the *current* ingredients, we are meeting four dietary requirements. However, given the dish, we can see there are more possibilities. .. code-block:: json { "data": { "tags": [ { "id": "16", "name": "glutenfree" }, { "id": "18", "name": "No meat" }, { "id": "21", "name": "nutfree" }, { "id": "247", "name": "eggfree" } ], "dishes": [ { "id": "171", "name": "Avocado Banana Kiwi Smoothie", "adaptableToTags": [ { "id": "16", "name": "glutenfree" }, { "id": "18", "name": "No meat" }, { "id": "19", "name": "lactosefree" }, { "id": "20", "name": "diabetic" }, { "id": "21", "name": "nutfree" }, { "id": "17", "name": "vegan" }, { "id": "247", "name": "eggfree" } ] } ] } } Now we will try and get some ingredient suggestions for meeting the ``vegan`` dietary requirement. We already know that tag has an id of **17**, so we will use that in the query. .. code-block:: query suggestIngredients($dish: ID, $ingredients: [ID]){ dishes(id: $dish){ id name suggestedIngredients(mode: ALL, contextIngredients: $ingredients, adaptToTags: [17]){ id name } } } In the response, ``cream`` was substituted with ``water`` which now makes the set of ingredients meet the requirement of being ``vegan``. .. code-block:: json { "data": { "dishes": [ { "id": "171", "name": "Avocado Banana Kiwi Smoothie", "suggestedIngredients": [ { "id": "17", "name": "avocado" }, { "id": "22", "name": "banana" }, { "id": "43", "name": "brown sugar" }, { "id": "163", "name": "kiwi" }, { "id": "385", "name": "water" } ] } ] } } In this case, the substituted ingredient was water, but let's say for some reason it was substituted with a nutcream. Then our ingredients, which were previously ``nutfree``, are not anymore. In those cases you could create a refresh query, to always be updated on which dietary requirements are *currently* met. .. code-block:: query refreshDiets($ingredients: [ID]){ tags(shared: {type: INGREDIENT, ids: $ingredients}, category: "dietary"){ id name } } In this case, we see the tag ``vegan`` was added, but also the tag ``lactosefree``. .. code-block:: json { "data": { "tags": [ { "id": "16", "name": "glutenfree" }, { "id": "17", "name": "vegan" }, { "id": "18", "name": "No meat" }, { "id": "19", "name": "lactosefree" }, { "id": "21", "name": "nutfree" }, { "id": "247", "name": "eggfree" } ] } } Lastly, instead of just having a set of ingredients, we can generate a recipe from them. .. code-block:: query recipe($dish: ID!, $ingredients: [ID]!){ recipe(dish: $dish, ingredients: $ingredients){ instructions{ text } } } And here are the instructions for it! .. code-block:: json { "data": { "recipe": { "instructions": [ { "text": "Peel and slice the banana and kiwi." }, { "text": "Scoop out the avocado." }, { "text": "Add the avocado, banana, brown sugar, water and kiwi to your blender and blend until smooth." }, { "text": "Serve the smoothie cold right away, or store it in the fridge up to 3 days." } ] } } }