Skip to content

Commit 77a9e60

Browse files
author
Kian Khoshnoodpour
committed
docs(wiki): workshop
1 parent b658883 commit 77a9e60

19 files changed

+2734
-63
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Setting up your development environment
2+
3+
This part is optional, you can use your own development environment and tools.
4+
5+
The development environment described here is the most commonly used one and the one we recommend.
6+
7+
1. Download and install [Visual Studio Code](https://code.visualstudio.com/) together with the [GraphQL plugin](https://marketplace.visualstudio.com/items?itemName=Prisma.vscode-graphql).
8+
1. Clone the [repository](https://kkhoshnoodpour@scm.ecom.ahold.nl/stash/scm/~maarten.van.oudenniel/sandbox-graphql.git).
9+
1. Run `yarn` from the root folder of the cloned folder
10+
1. Open the cloned folder using VSCode
11+
12+
Now we're all set to use GraphQL!
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
# Chapter 1: My first query
2+
3+
> [Frontend, Backend]
4+
5+
In this assignment we're going to add a new query that we can use in our application. We do this by:
6+
7+
1. Defining a new query and type in the GraphQL schema
8+
1. Implementing the resolver logic that actually gets and returns the data
9+
10+
Let's get started!
11+
12+
Create a new branch from `master`
13+
14+
```
15+
git checkout -b graphql-tutorial
16+
```
17+
18+
Then start the application.
19+
20+
```sh
21+
yarn dev
22+
```
23+
24+
## Assignment 1.1: Add a new query to the GraphQL schema
25+
26+
The GraphQL schema is the complete definition of the GraphQL API. Similar to swagger documentation it tells the developer what operations (queries) they can perform. And what the return types are for these operations.
27+
28+
Our demo application uses NextJS and its convention to store the schema in: `pages/api/graphql/schema.ts`.
29+
30+
**Update this file to contain**:
31+
32+
- A new type that defines what we want to show in our UI. Examples of types could be: A favorite list, a product, an order
33+
- A new query that returns a collection
34+
35+
Assuming you started the application before saving the file, you will see that the running process will pickup your changes and update the files:
36+
37+
- `_schema.graphql`
38+
- `codegen/_graphql.tsx`
39+
- `codegen/_resolvers.tsx`
40+
41+
> Alternatively you can run the command: `yarn generate` to manually run the update. These files are auto-generated from the GraphQL schema. And are used to strongly-type the application, as well as provide utility functions we can use in our app. For more information on how this works see the `codegen` section in the setup docs.
42+
43+
In these files you should now see the generated GraphQL definitions and TypeScript types that were generated based on what you defined in `schema.ts`.
44+
45+
## Assignment 1.2: Implement the resolver logic for our new query
46+
47+
Now that we have our query and type in place, we have to write the code that gets the data and returns it.
48+
49+
**Open the file `pages/api/graphql/resolvers.ts`**
50+
51+
If you're running the app your editor should already tell you there's something wrong in this file, **The new query we just added isn't included in the resolver**.
52+
53+
Add the missing query, using the exact same name used as in the `schema.ts` file. Return an array of your defined object.
54+
55+
## Assignment 1.3: Run your query in the playground
56+
57+
Now you should be able to run your query in the GraphQL playground environment: <http://localhost:3000/api/graphql>.
58+
59+
> The playground provides an environment to test queries. It includes auto-complete, as you start typing it will provide suggestions. Click on the `schema` button on the right to see the entire schema.
60+
61+
Enter your query then, click the run button and see your data!
62+
63+
> GraphQL supports _query-what-you-need_, removing fields from your query will prevent that data being sent to you.
64+
65+
Do you see data? Great! You just wrote your first query.
66+
67+
If you didn't. No worries, check out the solution for a working example. Try to fix your code by looking at the example. You can also use the solution branch from chapter 1 to continue with chapter 2.
68+
69+
# Chapter 1 - Solution: My first query
70+
71+
Branch `chapter-1-solution`
72+
73+
A possible solution would be to display the users favorite lists. Users create favorite lists to store their favorite products. When they're shopping they can use their favorite lists to fill their shopping cart quickly.
74+
75+
## Assignment 1.1 - Solution: Add a new query to the GraphQL schema
76+
77+
For our query and type we defined the following in
78+
79+
`pages/api/graphql/schema.ts`:
80+
81+
```
82+
# all our queries are defined on the type Query
83+
type Query {
84+
"""
85+
Have a simple example
86+
"""
87+
simple: String
88+
"""
89+
Get all the favorite lists this user has made
90+
"""
91+
lists: [List!]
92+
}
93+
94+
"""
95+
Favorite list
96+
"""
97+
type List {
98+
"""
99+
Id of list
100+
"""
101+
id: Int! # a field named id with type integer that may not be null
102+
"""
103+
Description entered by user
104+
"""
105+
description: String!
106+
}
107+
```
108+
109+
We have two types: **Query** and **List**.
110+
111+
All queries must be defined under the **Query** type.
112+
113+
Custom types get their own type definition.
114+
115+
## Assignment 1.2 - Solution: Implement the resolver logic for our new query
116+
117+
To implement the resolver logic we return some mocked data
118+
119+
`pages/api/graphql/resolvers.ts`
120+
121+
```typescript
122+
const query: QueryResolvers = {
123+
simple: () => {
124+
console.log('[server] GraphQL server query: simple');
125+
return 'Welcome to the AH GraphQL workshop';
126+
},
127+
lists: () => [
128+
{
129+
id: 0,
130+
description: 'Shopping List',
131+
},
132+
{
133+
id: 1,
134+
description: 'Chocolate',
135+
},
136+
],
137+
};
138+
```
139+
140+
## Assignment 1.3 - Solution: Run your query in the playground
141+
142+
Now we can query the fields on type **List** from the playground, using the **lists** query.
143+
144+
<http://localhost:3000/api/graphql>:
145+
146+
```graphql
147+
{
148+
lists {
149+
id
150+
description
151+
}
152+
}
153+
```
Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
# Chapter 2 - Calling GraphQL from React
2+
3+
> [Frontend]
4+
5+
In this chapter we'll use the GraphQL query we defined in chapter 1 and display it in our React application.
6+
7+
## Assignment 2.1: Write the query
8+
9+
Create a new module folder in `modules/my-module` and add a file called `query.graphql`
10+
11+
`modules/my-module/query.graphql`
12+
13+
In this file we're going to write our first query. We write the query in GraphQL, when writing queries in our application we have to name our query:
14+
15+
```graphql
16+
query myQuery {
17+
...the_actual_query
18+
}
19+
```
20+
21+
For example, taking the schema from the `chapter-1-solution` our query could look like this:
22+
23+
```graphql
24+
query lists {
25+
lists {
26+
id
27+
description
28+
}
29+
}
30+
```
31+
32+
> If you're using VSCode together with the GraphQL plugin you will get auto-complete suggestions in the editor as you're typing queries. Use cmd+space to trigger suggestions manually.
33+
34+
After saving this file, the running application will pick up the changes and generate TypeScript types and React hooks. These can be found in: `codegen/graphql.tsx`. We'll be using these hooks and types to build our UI. See the appendix to learn more about code generation.
35+
36+
## Assignment 2.2: Use the query in a component
37+
38+
Next let's create a component and display our data. Create a React component:
39+
40+
`modules/my-module/my-component.tsx`
41+
42+
A blank component looks like this:
43+
44+
```tsx
45+
import React from 'react';
46+
47+
export const MyComponent: React.FC = () => {
48+
return null;
49+
};
50+
```
51+
52+
Now we can the generated React hook imported from `schema/graphql.tsx` to connect to GraphQL:
53+
54+
```ts
55+
import { useMyQuery } from '../../codegen/_graphql';
56+
57+
// add to the body of your component
58+
const { loading, error, data } = useMyQuery();
59+
```
60+
61+
The generated hook among others will give you 3 state variables: `loading`, `error`, `data`. These state variables describe the state of the GraphQL query you're trying to perform.
62+
63+
> Tip: Write down `,[space]` after `data` and press `ctrl+space` to get suggestions for other values you can use.
64+
65+
You can use these state variables to determine what to display, for instance you can show a loading spinner if the query is still running and hasn't received data. Or you can display an error message. For example:
66+
67+
```tsx
68+
if (loading) {
69+
return <p>Loading...</p>;
70+
}
71+
72+
if (error) {
73+
return <p>Error: {error}</p>;
74+
}
75+
76+
if (!data || !data.queryName) {
77+
return <p>Erorr: Unknown</p>;
78+
}
79+
80+
return; // do something with the data
81+
```
82+
83+
To style the components you can either use [styled components](https://styled-components.com/docs) or include the css as a style attribute on the JSX element:
84+
85+
```tsx
86+
// using styled components
87+
import styled from 'styled-components';
88+
89+
// we define a simple box
90+
const Box = styled.div`
91+
padding: 8px;
92+
margin: 0 0 24px;
93+
border: 1px solid #eee;
94+
`;
95+
96+
// or just use the style tag:
97+
<div
98+
style={{
99+
padding: '8px',
100+
margin: '0 0 24px',
101+
border: '1px solid #eee',
102+
}}
103+
>
104+
...your content
105+
</div>;
106+
```
107+
108+
To finish the assignment display your data in some way in the component. Then create another component in `pages` and use your newly created component:
109+
110+
`pages/my-page.tsx`
111+
112+
```tsx
113+
import { NextPage } from 'next';
114+
import { withApollo } from '../lib/apollo';
115+
import { MyComponent } from '../modules/my-module/my-component';
116+
117+
const MyPage: NextPage = () => {
118+
return <MyComponent />;
119+
};
120+
121+
// be sure to include this line
122+
export default withApollo(MyPage);
123+
```
124+
125+
You can now see your page, component and hopefully your data from GraphQL at <http://localhost:3000/my-page>.
126+
127+
# Chapter 2 - Solution: Calling GraphQL from React
128+
129+
Branch `chapter-2-solution`
130+
131+
Continued from the solution from chapter 1 on branch `chapter-1-solution`.
132+
133+
## Assignment 2.1 - Solution: Write the query
134+
135+
We create a query to retrieve all our favorite lists:
136+
137+
`modules/list/lists.graphql`
138+
139+
```graphql
140+
query lists {
141+
lists {
142+
id
143+
description
144+
}
145+
}
146+
```
147+
148+
## Assignment 2.2 - Solution: Use the query in a component
149+
150+
Next we create a component that displays all the favorite lists in a box.
151+
152+
`modules/list/list-overview.tsx`
153+
154+
```tsx
155+
import React from 'react';
156+
import styled from 'styled-components';
157+
// we're importing a generated React hook
158+
// the hook is actually a wrapper around the useQuery hook found in the apollo client
159+
import { useListsQuery } from '../../codegen/_graphql';
160+
161+
// create a simple box to show our data in using styled components
162+
const List = styled.div`
163+
padding: 8px;
164+
margin: 0 0 24px;
165+
border: 1px solid #eee;
166+
`;
167+
168+
export const ListOverview: React.FC = () => {
169+
// the hook performs the call to the graphql server
170+
// and gives us state variables that we can use in our app
171+
const { loading, error, data } = useListsQuery();
172+
173+
// we can decide what to show based on the state
174+
if (loading) {
175+
return <p>Loading...</p>;
176+
}
177+
178+
if (error) {
179+
return <p>Error: {error}</p>;
180+
}
181+
182+
if (!data || !data.lists) {
183+
return <p>Erorr: Unknown</p>;
184+
}
185+
186+
// and tells us when we really have data
187+
// now we really have data that we can use
188+
return (
189+
<>
190+
{data.lists.map((list) => (
191+
<List key={list.id}>{list.description}</List>
192+
))}
193+
</>
194+
);
195+
};
196+
```
197+
198+
Finally we create a page.
199+
200+
`pages/favorites.tsx`:
201+
202+
```tsx
203+
import { NextPage } from 'next';
204+
import { withApollo } from '../lib/apollo';
205+
import { ListOverview } from '../modules/list/list-overview';
206+
207+
const ListsPage: NextPage = () => {
208+
return <ListOverview />;
209+
};
210+
211+
export default withApollo(ListsPage);
212+
```
213+
214+
Now we can go to <http://localhost:3000/favorites> and see all the users favorite lists in a nice box.

0 commit comments

Comments
 (0)