Add notes from Apollo GraphQL courses
This commit is contained in:
parent
2da598d3d3
commit
05a6d17a8e
4 changed files with 245 additions and 4 deletions
88
Databases/GraphQL/Apollo/Apollo_Client.md
Normal file
88
Databases/GraphQL/Apollo/Apollo_Client.md
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
---
|
||||||
|
title: Apollo Client
|
||||||
|
categories:
|
||||||
|
- Databases
|
||||||
|
tags: [graph-ql, apollo]
|
||||||
|
---
|
||||||
|
|
||||||
|
# Apollo Client
|
||||||
|
|
||||||
|
Apollo Client is the client-side counterpart to [Apollo Server](/Databases/GraphQL/Apollo/Apollo_Server.md). We use it for managing queries and mutations from the frontend to our Apollo GraphQL server. It is specifically designed to work with React.
|
||||||
|
|
||||||
|
## Initializing the client
|
||||||
|
|
||||||
|
We initialise the client and set-up in memory caching to reduce network requests:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const client = new ApolloClient({
|
||||||
|
uri: "http://localhost:4000",
|
||||||
|
cache: new InMemoryCache(),
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
> The uri property must match the location of our Apollo server.
|
||||||
|
|
||||||
|
## Utilising the provider
|
||||||
|
|
||||||
|
Apollo Provides a top level application context that we can wrap our React app in. This will provide access to the client object from anywhere within the app, eg:
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
ReactDOM.render(
|
||||||
|
<ApolloProvider client={client}>
|
||||||
|
<GlobalStyles />
|
||||||
|
<Pages />
|
||||||
|
</ApolloProvider>,
|
||||||
|
document.getElementById("root")
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Running a query
|
||||||
|
|
||||||
|
### Query constants
|
||||||
|
|
||||||
|
To run a query against our server we must define a query contant first. We use a `gql` literal again:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { gql } from "@apollo/client";
|
||||||
|
const TRACKS = gql`
|
||||||
|
query GetTracks {
|
||||||
|
tracksForHome {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
thumbnail
|
||||||
|
length
|
||||||
|
modulesCount
|
||||||
|
author {
|
||||||
|
name
|
||||||
|
photo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
```
|
||||||
|
|
||||||
|
The convention is to name the query constant in `ALL_CAPS`.
|
||||||
|
|
||||||
|
### `useQuery` hook
|
||||||
|
|
||||||
|
The `useQuery` hook provides a straightforward wrapper for sending queries and receiving data back from the server.
|
||||||
|
|
||||||
|
When a component renders, `useQuery` returns an object from the Apollo Client that contains loading, error, and data properties.
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
const { loading, error, data } = useQuery(TRACKS);
|
||||||
|
|
||||||
|
const Tracks = () => {
|
||||||
|
const { loading, error, data } = useQuery(TRACKS);
|
||||||
|
|
||||||
|
if (loading) return "Loading...";
|
||||||
|
|
||||||
|
if (error) return `Error! ${error.message}`;
|
||||||
|
|
||||||
|
return <Layout grid>{JSON.stringify(data)}</Layout>;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
- We destructure the `loading, error, data` variables that are returned from the hook
|
||||||
|
- We pass in our query constant as an argument.
|
||||||
|
- In the example we just render the serialized data but we could of course pass the data as a prop and map through it in an embedded child component.
|
113
Databases/GraphQL/Apollo/Apollo_Server.md
Normal file
113
Databases/GraphQL/Apollo/Apollo_Server.md
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
---
|
||||||
|
title: Apollo Server
|
||||||
|
categories:
|
||||||
|
- Databases
|
||||||
|
tags: [graph-ql, apollo]
|
||||||
|
---
|
||||||
|
|
||||||
|
# Apollo Server
|
||||||
|
|
||||||
|
> Apollo Server is the part of the Apollo suite that we use to create the backend of a GraphQL project; a GraphQL server.
|
||||||
|
|
||||||
|
It is able to do the following:
|
||||||
|
|
||||||
|
- Receive an incoming GraphQL query from a client
|
||||||
|
- Validate that query against the server schema
|
||||||
|
- Populate the queried schema fields
|
||||||
|
- Return the fields as a response
|
||||||
|
|
||||||
|
## Example schema
|
||||||
|
|
||||||
|
We will use the following schema in the examples
|
||||||
|
|
||||||
|
```js
|
||||||
|
const typeDefs = gql`
|
||||||
|
type Query {
|
||||||
|
"Get tracks array for homepage grid"
|
||||||
|
tracksForHome: [Track!]!
|
||||||
|
}
|
||||||
|
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
module.exports = typeDefs;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Setting up the server
|
||||||
|
|
||||||
|
```js
|
||||||
|
const { ApolloServer } = require("apollo-server");
|
||||||
|
const typeDefs = require("./schema");
|
||||||
|
const server = new ApolloServer({ typeDefs });
|
||||||
|
|
||||||
|
server.listen().then(() => {
|
||||||
|
console.log(`
|
||||||
|
Server is running!
|
||||||
|
Listening on port 4000
|
||||||
|
Query at http://localhost:4000
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
When we access the local URL we are able to access the Apollo server using the Explorer GUI. This automatically loads our schema and is basically a more fancy version of GraphiQL:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
It makes it easy to read descriptions of the dataypes and to construct queries by clicking to insert fields.
|
||||||
|
|
||||||
|
### Adding some mock data
|
||||||
|
|
||||||
|
We are not connected to a database yet but we can create a mock that will enable us to run test queries.
|
||||||
|
|
||||||
|
We do this just by updating the Apollo Server options. We can either use generic dummy data or provide our own mock.
|
||||||
|
|
||||||
|
#### Generic mock
|
||||||
|
|
||||||
|
```js
|
||||||
|
const server = new ApolloServer({ typeDefs, mocks: true });
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Custom mock
|
||||||
|
|
||||||
|
```js
|
||||||
|
const mocks = {
|
||||||
|
Track: () => ({
|
||||||
|
id: () => "track_01",
|
||||||
|
title: () => "Astro Kitty, Space Explorer",
|
||||||
|
author: () => {
|
||||||
|
return {
|
||||||
|
name: "Grumpy Cat",
|
||||||
|
photo:
|
||||||
|
"https://res.cloudinary.com/dety84pbu/image/upload/v1606816219/kitty-veyron-sm_mctf3c.jpg",
|
||||||
|
};
|
||||||
|
},
|
||||||
|
thumbnail: () =>
|
||||||
|
"https://res.cloudinary.com/dety84pbu/image/upload/v1598465568/nebula_cat_djkt9r.jpg",
|
||||||
|
length: () => 1210,
|
||||||
|
modulesCount: () => 6,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
const server = new ApolloServer({ typeDefs, mocks });
|
||||||
|
```
|
|
@ -7,7 +7,7 @@ tags: [graph-ql]
|
||||||
|
|
||||||
# Creating a GraphQL server
|
# Creating a GraphQL server
|
||||||
|
|
||||||
> We will use Node.js to create a basic GraphQL server that will serve data from a product database
|
> We will use Node.js to create a basic GraphQL server that will serve data from a product database.
|
||||||
|
|
||||||
Our server will allow us to add products to a database through a mutatation and to query the products that we have added. We will use a JS object instead of a real database.
|
Our server will allow us to add products to a database through a mutatation and to query the products that we have added. We will use a JS object instead of a real database.
|
||||||
|
|
||||||
|
@ -226,7 +226,11 @@ mutation {
|
||||||
soldout: false
|
soldout: false
|
||||||
stores: [{ store: "London" }]
|
stores: [{ store: "London" }]
|
||||||
}
|
}
|
||||||
)
|
) {
|
||||||
|
price
|
||||||
|
name
|
||||||
|
soldout
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -234,12 +238,13 @@ This is represented in GraphiQL as follows:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
// TODO: Add bit about the value we want returned see 8:20 and explain what is returned
|
We should always return something, even if we are applying mutation, hence we add the properties at the bottom as the ones we want to return.
|
||||||
|
|
||||||
### Returning a product through a query
|
### Returning a product through a query
|
||||||
|
|
||||||
```graphql
|
```graphql
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
// Add new image of this working in GraphiQL
|
// Add new image of this working in GraphiQL
|
||||||
|
|
|
@ -8,7 +8,9 @@ tags: [graph-ql]
|
||||||
|
|
||||||
SDL is the formal name for the syntax of GraphQL schemas.
|
SDL is the formal name for the syntax of GraphQL schemas.
|
||||||
|
|
||||||
A schema is a collection of object types that contain fields. Each field has a type of its own. A field's type can be a primitive/scalar value (such as an Int or a String), or it can be another object type (just like a custom type in TS).
|
## Types
|
||||||
|
|
||||||
|
A schema is a collection of object types that contain fields. Each field has a type of its own. A field's type can be a primitive/scalar value (such as an `Int` or a `String`), or it can be another object type (just like a custom type in TS).
|
||||||
|
|
||||||
A schema's type can be non-nullable which is to say, a required field. We indicate this with `!`.
|
A schema's type can be non-nullable which is to say, a required field. We indicate this with `!`.
|
||||||
|
|
||||||
|
@ -30,6 +32,39 @@ type Pet {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Queries
|
||||||
|
|
||||||
|
A query is also a schema type but of a special sort.
|
||||||
|
|
||||||
|
> The fields of this type are entry points into the rest of the schema. These are the top-level fields that the client can query for.
|
||||||
|
|
||||||
|
For example if we had this type:
|
||||||
|
|
||||||
|
```graphql
|
||||||
|
type Track {
|
||||||
|
id: ID!
|
||||||
|
title: String!
|
||||||
|
author: Author!
|
||||||
|
thumbnail: String
|
||||||
|
length: Int
|
||||||
|
modulesCount: Int
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
We could define a type to access a give `Track` as follows:
|
||||||
|
|
||||||
|
```graphql
|
||||||
|
type Query {
|
||||||
|
tracksForHomePage: [Track!]!
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Then use this type as the basis for a query:
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
## Descriptions
|
## Descriptions
|
||||||
|
|
||||||
Descriptions are comments that allow you to document your Schema
|
Descriptions are comments that allow you to document your Schema
|
||||||
|
|
Loading…
Add table
Reference in a new issue