From 05a6d17a8ee0c24d1dfee1cfd3b96ad4783349f7 Mon Sep 17 00:00:00 2001 From: Thomas Bishop Date: Fri, 11 Nov 2022 16:30:31 +0000 Subject: [PATCH] Add notes from Apollo GraphQL courses --- Databases/GraphQL/Apollo/Apollo_Client.md | 88 ++++++++++++++ Databases/GraphQL/Apollo/Apollo_Server.md | 113 ++++++++++++++++++ .../GraphQL/Creating_a_GraphQL_server.md | 11 +- .../GraphQL/Schema_Definition_Language.md | 37 +++++- 4 files changed, 245 insertions(+), 4 deletions(-) create mode 100644 Databases/GraphQL/Apollo/Apollo_Client.md create mode 100644 Databases/GraphQL/Apollo/Apollo_Server.md diff --git a/Databases/GraphQL/Apollo/Apollo_Client.md b/Databases/GraphQL/Apollo/Apollo_Client.md new file mode 100644 index 0000000..dc9afcb --- /dev/null +++ b/Databases/GraphQL/Apollo/Apollo_Client.md @@ -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( + + + + , + 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 {JSON.stringify(data)}; +}; +``` + +- 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. diff --git a/Databases/GraphQL/Apollo/Apollo_Server.md b/Databases/GraphQL/Apollo/Apollo_Server.md new file mode 100644 index 0000000..ee361fa --- /dev/null +++ b/Databases/GraphQL/Apollo/Apollo_Server.md @@ -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: + +![](/img/apollo-explorer.png) + +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 }); +``` diff --git a/Databases/GraphQL/Creating_a_GraphQL_server.md b/Databases/GraphQL/Creating_a_GraphQL_server.md index d1bec8d..03ecb4a 100644 --- a/Databases/GraphQL/Creating_a_GraphQL_server.md +++ b/Databases/GraphQL/Creating_a_GraphQL_server.md @@ -7,7 +7,7 @@ tags: [graph-ql] # 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. @@ -226,7 +226,11 @@ mutation { soldout: false stores: [{ store: "London" }] } - ) + ) { + price + name + soldout + } } ``` @@ -234,12 +238,13 @@ This is represented in GraphiQL as follows: ![](/img/graphql3.png) -// 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 ```graphql + ``` // Add new image of this working in GraphiQL diff --git a/Databases/GraphQL/Schema_Definition_Language.md b/Databases/GraphQL/Schema_Definition_Language.md index 7136c14..97bdbe9 100644 --- a/Databases/GraphQL/Schema_Definition_Language.md +++ b/Databases/GraphQL/Schema_Definition_Language.md @@ -8,7 +8,9 @@ tags: [graph-ql] 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 `!`. @@ -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 are comments that allow you to document your Schema