[1]: Apollo Server was the library I used as a reference for capabilities, it is used by many Javascript libraries under the hood like TypeGraphQL and NestJS
[2]: The @deprecated declaration can be used to "soft remove" fields, adding new fields can be done without impacting existing queries, because they won't be resolved by that query
[3]: Apollo Client and urql were the libraries used for reference; however, libraries exist for many languages.
GET /recipe/{id}
{
id: number,
title: string,
description: string,
ingredients: number[]
}
GET /ingredient/{id}
{
id: number,
title: string,
description: string
}
async function getData(recipeId: number) {
// Request #1
const recipe = await fetch(`/recipes/${recipeId}`)
.then(r => r.json());
const ingredients = await Promise.all(
// Request n?
recipe.map(iId => fetch(`/ingredient/${iId}`)
.then(i => i.json()))
)
return {
...recipe,
ingredients
}
}
async function getData(recipeId: number) {
// Request #1
const recipe = await fetch(`/recipes/${recipeId}`)
.then(r => r.json());
const ingredients = await Promise.all(
// Request n?
recipe.map(iId => fetch(`/ingredient/${iId}`)
.then(i => i.json()))
)
return {
...recipe,
ingredients
}
}
The Apollo Server Docs have a great section on schemas that goes more in depth than this talk
type Query {
recipe(id: Int!): Recipe
recipes: [Recipe!]!
}
type Mutation {
updateRecipe(data: RecipeInput!, id: Int!): Recipe!
}
type Recipe {
id: Float!
title: String!
description: String
ingredients: [Ingredient]!
}
input RecipeInput {
description: String
title: String
}
The server exposes this as a standardized set of capabilities
type Query {
recipe(id: Int!): Recipe
recipes: [Recipe!]!
}
type Mutation {
updateRecipe(data: RecipeInput!, id: Int!): Recipe!
}
type Recipe {
id: Float!
title: String!
description: String
ingredients: [Ingredient]!
}
input RecipeInput {
description: String
title: String
}
Our operations are declared under the Query and Mutation types
(Subscriptions would live in the Subscription type)
type Query {
recipe(id: Int!): Recipe
recipes: [Recipe!]!
}
type Mutation {
updateRecipe(data: RecipeInput!, id: Int!): Recipe!
}
type Recipe {
id: Float!
title: String!
description: String
ingredients: [Ingredient]!
}
input RecipeInput {
description: String
title: String
}
The Recipe model is declared here with the keyword type
type Query {
recipe(id: Int!): Recipe
recipes: [Recipe!]!
}
type Mutation {
updateRecipe(data: RecipeInput!, id: Int!): Recipe!
}
type Recipe {
id: Float!
title: String!
description: String
ingredients: [Ingredient]!
}
input RecipeInput {
description: String
title: String
}
The Recipe Input is declared here with the input type - this is a
model that the server consumes
async function getData(recipeId: number) {
const query = gql`
query recipeView($id: Float!) {
recipe(id: $id) {
title
description
ingredients {
title
description
}
}
}`
// Request #1
return await gqlClient
.query(query, {id: recipeId})
.toPromise()
}
async function getData(recipeId: number) {
const query = gql`
query recipeView($id: Float!) {
recipe(id: $id) {
title
description
ingredients {
title
description
}
}
}`
// Request #1
return await gqlClient
.query(query, {id: recipeId})
.toPromise()
}