From 03b6c68b93caf9aaf937db6cb65ddb641378b8c2 Mon Sep 17 00:00:00 2001 From: Thomas Bishop Date: Fri, 18 Nov 2022 19:39:00 +0000 Subject: [PATCH] More Apollo notes --- Databases/GraphQL/Apollo/Apollo_Client.md | 8 +- Databases/GraphQL/Apollo/Apollo_Server.md | 59 +++++------ .../Using_arguments_with_Apollo_Client.md | 100 +++++++++++++++++- 3 files changed, 128 insertions(+), 39 deletions(-) diff --git a/Databases/GraphQL/Apollo/Apollo_Client.md b/Databases/GraphQL/Apollo/Apollo_Client.md index cbab9bb..7ec9333 100644 --- a/Databases/GraphQL/Apollo/Apollo_Client.md +++ b/Databases/GraphQL/Apollo/Apollo_Client.md @@ -40,6 +40,12 @@ ReactDOM.render( ## Running a query +### Queries as entry points + +From the client point of view, the queries in the schema are _entry points_. Although the queries exist in the schema, this alone is not sufficient for them to be entry points. Remember a schema is just a specification or contract between the frontend and the backend, it is not itself executable code. + +Therefore, for each query in the schema we must write a frontend implementation. We do this with **query constants**. The frontend implementation has a backend analogue: the [resolver](/Databases/GraphQL/Apollo/Apollo_Server.md#implementing-resolvers) that is invoked when the frontend issues a query. The schema standardises this relationship so that every query on the client must have a corresponding resolver on the backend. + ### Query constants To run a query against our server we must define a query contant first. We use a `gql` literal again: @@ -65,7 +71,7 @@ const TRACKS = gql` The convention is to name the query constant in `ALL_CAPS`. -> Note that the name of the query on the client doesn't have to match the query type defined in the schema however it should reference it on the second line (`tracksFormHome) +> Note that the name of the query on the client doesn't have to match the query type defined in the schema (there is no `GetTracks` in the schema), this is just a client-side designator. However it should reference the schema on the second line (`tracksForHome`). ### `useQuery` hook diff --git a/Databases/GraphQL/Apollo/Apollo_Server.md b/Databases/GraphQL/Apollo/Apollo_Server.md index a372318..c5bf8b7 100644 --- a/Databases/GraphQL/Apollo/Apollo_Server.md +++ b/Databases/GraphQL/Apollo/Apollo_Server.md @@ -18,45 +18,36 @@ It is able to do the following: ## Example schema -We will use the following schema in the examples - -// +We will use the following schema in the examples. ```js const typeDefs = gql` - type Query { - "Get tracks array for homepage grid" - tracksForHome: [Track!]! - } - -// TODO, rewrite this so I can get syntax highlighting - "A track is a group of Modules that teaches about a specific topic" - type Track { - id: ID! - "The track's title" - title: String! - "The track's main author" - author: Author! - "The track's main illustration to display in track card or track page detail" - thumbnail: String - "The track's approximate length to complete, in minutes" - length: Int - "The number of modules this track contains" - modulesCount: Int - } - - "Author of a complete Track" - type Author { - id: ID! - "Author's first and last name" - name: String! - "Author's profile picture url" - photo: String - } + " Our schema types will be nested here `; module.exports = typeDefs; ``` +```js +type Query { + tracksForHome: [Track!]! +} + +type Track { + id: ID! + title: String! + author: Author! + thumbnail: String + length: Int + modulesCount: Int +} + +type Author { + id: ID! + name: String! + photo: String +} +``` + ## Setting up the server We instantiate an `ApolloServer` instance and pass our schema to it. We then subscribe to it with a [listener](/Programming_Languages/Node/Modules/Core/Node_JS_events_module.md#extending-the-eventemitter-class). @@ -241,6 +232,6 @@ const resolvers = { }; ``` -- We keep `Track` outside of `Query` because it has no corresponding query in the schema and we must always match the schema. `Track` is a self-standing field so the resolver must **match this schema shape**. The query `getTracksForHome` references `Track` but it is a separate field. +- We keep `Track` outside of `Query` because it has no corresponding query in the schema and we must always match the schema. - We invoke the `context` again when we destructure `dataSources`. -- This time we utilise the `args` parameter in the resolver since an `id` will be provided from the client to return a specific author. +- This time we utilise the `args` parameter in the resolver since an `id` will be provided as a client-side [argument](/Databases/GraphQL/Apollo/Using_arguments_with_Apollo_Client.md) to return a specific author. diff --git a/Databases/GraphQL/Apollo/Using_arguments_with_Apollo_Client.md b/Databases/GraphQL/Apollo/Using_arguments_with_Apollo_Client.md index 3abe3d1..bde47f0 100644 --- a/Databases/GraphQL/Apollo/Using_arguments_with_Apollo_Client.md +++ b/Databases/GraphQL/Apollo/Using_arguments_with_Apollo_Client.md @@ -7,17 +7,31 @@ tags: [graph-ql, apollo] # Using arguments with Apollo Client +## What are arguments? + +- An argument is a value you provide for a particular field in a query. +- The schema must define the arguments that a field accepts (if any) +- The resolver invokes a field's provided arguments to determine how to return specific data +- Some example use cases of arguments: + - retrieve specific objects + - filter through a set of objects + - transform a field's returned value + +## Updated schema + In order to demonstrate arguments we need to expand the [original schema](/Databases/GraphQL/Apollo/Apollo_Server.md#example-schema). -Remember a Track is a group of Modules that teaches about a specific topic. We are going to add: +Remember a Track is a group of modules that teaches about a specific topic. We are going to add: - `description` and `numberOfViews` fields to the original `Track` type - A new `Module` type - A field `modules` to the `Track` type that will be an array of type `Module` -## Updated schema - ```js +type Query { + tracksForHome: [Track!]! +} + type Track { id: ID! title: String! @@ -40,5 +54,83 @@ type Author { id: ID! name: String! photo: String - } +} +``` + +## Adding additional query + +> Currently we only have one query in the schema (`tracksForHome`) and this returns an array of all the tracks. To demonstrate arguments we want to return a specific track by its `id`. We are going to add a query that enables this. + +```js +type Query { + track(id: ID!): Track +} +``` + +This query will take an `id` as an argument and the resolver will match the `id` to a given track and return that `Track`. + +To define an argument for a field in the schema we add parentheses after the field name. In the parentheses we write the name of the argument and its type. If we have more than one argument we can separate them with commas. + +## Create resolver for new query + +Now we have to create a resolver for our new `track` query. We will quickly run through the [server-side process](/Databases/GraphQL/Apollo/Apollo_Server.md). + +### Update our `RESTDataSource` + +```js +class TrackAPI extends RESTDataSource { + constructor() {...} + getTracksForHome() {...} + getAuthor(authorId) {...} + + getTrack(trackId){ + return this.get(`track/${trackId}`); + } +} + +``` + +### Add resolver to `resolvers.js` + +```js +const resolvers = { + Query: { + tracksForHome: (_, __, { dataSources }) => { + return dataSources.trackApi.getTracksForHome(); + }, + track: (_, { id }, { dataSources }) => { + return dataSources.trackAPI.getTrack(id); + }, + }, + Track: { + author: ({ authorId }, _, { dataSources }) => { + return dataSources.trackApi.getAuthor(authorId); + }, + }, +}; +``` + +### Making a query + +With the server changes complete, we can now issue a query with an argument from the client: + +```gql +query track(id: 'xyz'){ + title +} +``` + +This will return the `title` field from the track with the specific id. This query complies with the schema since the `Track` type has the field `title` + +### Resolver chains + +What about the following query: + +```gql +query track(id: 'xyz'){ + title + author { + name + } +} ```