More Apollo notes

This commit is contained in:
Thomas Bishop 2022-11-18 19:39:00 +00:00
parent 6573d2964e
commit 03b6c68b93
3 changed files with 128 additions and 39 deletions

View file

@ -40,6 +40,12 @@ ReactDOM.render(
## Running a query ## 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 ### Query constants
To run a query against our server we must define a query contant first. We use a `gql` literal again: 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`. 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 ### `useQuery` hook

View file

@ -18,43 +18,34 @@ It is able to do the following:
## Example schema ## Example schema
We will use the following schema in the examples We will use the following schema in the examples.
//
```js ```js
const typeDefs = gql` const typeDefs = gql`
" Our schema types will be nested here
`;
module.exports = typeDefs;
```
```js
type Query { type Query {
"Get tracks array for homepage grid"
tracksForHome: [Track!]! 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 { type Track {
id: ID! id: ID!
"The track's title"
title: String! title: String!
"The track's main author"
author: Author! author: Author!
"The track's main illustration to display in track card or track page detail"
thumbnail: String thumbnail: String
"The track's approximate length to complete, in minutes"
length: Int length: Int
"The number of modules this track contains"
modulesCount: Int modulesCount: Int
} }
"Author of a complete Track"
type Author { type Author {
id: ID! id: ID!
"Author's first and last name"
name: String! name: String!
"Author's profile picture url"
photo: String photo: String
} }
`;
module.exports = typeDefs;
``` ```
## Setting up the server ## Setting up the server
@ -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`. - 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.

View file

@ -7,17 +7,31 @@ tags: [graph-ql, apollo]
# Using arguments with Apollo Client # 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). 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 - `description` and `numberOfViews` fields to the original `Track` type
- A new `Module` type - A new `Module` type
- A field `modules` to the `Track` type that will be an array of type `Module` - A field `modules` to the `Track` type that will be an array of type `Module`
## Updated schema
```js ```js
type Query {
tracksForHome: [Track!]!
}
type Track { type Track {
id: ID! id: ID!
title: String! title: String!
@ -42,3 +56,81 @@ type Author {
photo: 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
}
}
```