Skip to content

Commit 182bbfa

Browse files
committed
tweaks 8ab
1 parent ee64438 commit 182bbfa

File tree

5 files changed

+48
-79
lines changed

5 files changed

+48
-79
lines changed

src/content/8/en/part8a.md

Lines changed: 21 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -250,17 +250,17 @@ Let's implement a GraphQL server with today's leading library: [Apollo Server](h
250250
Create a new npm project with _npm init_ and install the required dependencies.
251251

252252
```bash
253-
npm install apollo-server@3.10.1 graphql
253+
npm install @apollo/server graphql
254254
```
255255

256-
**Note** at the time of writing (10th Dec 2022) the code used in this part is not fully compatible with the new version of the Apollo Server, and because of this, if you want everything to work smoothly you should install the version _3.10.1_. Material shall be updated to use the most recent Apollo Server in early 2023.
257256

258257
Also create a `index.js` file in your project's root directory.
259258

260259
The initial code is as follows:
261260

262261
```js
263-
const { ApolloServer, gql } = require('@apollo/server')
262+
const { ApolloServer } = require('@apollo/server')
263+
const { startStandaloneServer } = require('@apollo/server/standalone')
264264

265265
let persons = [
266266
{
@@ -285,7 +285,7 @@ let persons = [
285285
},
286286
]
287287

288-
const typeDefs = gql`
288+
const typeDefs = `
289289
type Person {
290290
name: String!
291291
phone: String
@@ -315,12 +315,14 @@ const server = new ApolloServer({
315315
resolvers,
316316
})
317317

318-
server.listen().then(({ url }) => {
318+
startStandaloneServer(server, {
319+
listen: { port: 4000 },
320+
}).then(({ url }) => {
319321
console.log(`Server ready at ${url}`)
320322
})
321323
```
322324

323-
The heart of the code is an _ApolloServer_, which is given two parameters:
325+
The heart of the code is an [ApolloServer](https://www.apollographql.com/docs/apollo-server/api/apollo-server/), which is given two parameters:
324326

325327
```js
326328
const server = new ApolloServer({
@@ -331,7 +333,7 @@ const server = new ApolloServer({
331333

332334
The first parameter, _typeDefs_, contains the GraphQL schema.
333335

334-
The second parameter is an object, which contains the [resolvers](https://www.apollographql.com/tutorials/fullstack-quickstart/04-writing-query-resolvers) of the server. These are the code, which defines <i>how</i> GraphQL queries are responded to.
336+
The second parameter is an object, which contains the [resolvers](https://www.apollographql.com/docs/apollo-server/data/resolvers/) of the server. These are the code, which defines <i>how</i> GraphQL queries are responded to.
335337

336338
The code of the resolvers is the following:
337339

@@ -426,13 +428,10 @@ The second parameter, _args_, contains the parameters of the query.
426428
The resolver then returns from the array _persons_ the person whose name is the same as the value of <i>args.name</i>.
427429
The resolver does not need the first parameter _root_.
428430

429-
430-
431-
In fact, all resolver functions are given [four parameters](https://www.graphql-tools.com/docs/resolvers#resolver-function-signature). With JavaScript, the parameters don't have to be defined if they are not needed. We will be using the first and the third parameter of a resolver later in this part.
431+
In fact, all resolver functions are given [four parameters](https://www.graphql-tools.com/docs/resolvers#resolver-function-signature). With JavaScript, the parameters don't have to be defined if they are not needed. We will be using the first and the third parameter of a resolver later in this part.
432432

433433
### The default resolver
434434

435-
436435
When we do a query, for example
437436

438437
```js
@@ -453,7 +452,6 @@ We have so far only defined resolvers for fields of the type <i>Query</i>, so fo
453452
Because we did not define resolvers for the fields of the type <i>Person</i>, Apollo has defined [default resolvers](https://www.graphql-tools.com/docs/resolvers/#default-resolver) for them.
454453
They work like the one shown below:
455454

456-
457455
```js
458456
const resolvers = {
459457
Query: {
@@ -473,13 +471,10 @@ const resolvers = {
473471
}
474472
```
475473

476-
477474
The default resolver returns the value of the corresponding field of the object. The object itself can be accessed through the first parameter of the resolver, _root_.
478475

479-
480476
If the functionality of the default resolver is enough, you don't need to define your own. It is also possible to define resolvers for only some fields of a type, and let the default resolvers handle the rest.
481477

482-
483478
We could for example define that the address of all persons is
484479
<i>Manhattan New York</i> by hard-coding the following to the resolvers of the street and city fields of the type <i>Person</i>:
485480

@@ -516,10 +511,8 @@ type Query {
516511
}
517512
```
518513

519-
520514
so a person now has a field with the type <i>Address</i>, which contains the street and the city.
521515

522-
523516
The queries requiring the address change into
524517

525518
```js
@@ -565,7 +558,6 @@ let persons = [
565558
]
566559
```
567560

568-
569561
The person-objects saved in the server are not exactly the same as the GraphQL type <i>Person</i> objects described in the schema.
570562

571563
Contrary to the <i>Person</i> type, the <i>Address</i> type does not have an <i>id</i> field, because they are not saved into their own separate data structure in the server.
@@ -615,10 +607,8 @@ type Mutation {
615607
}
616608
```
617609

618-
619610
The Mutation is given the details of the person as parameters. The parameter <i>phone</i> is the only one which is nullable. The Mutation also has a return value. The return value is type <i>Person</i>, the idea being that the details of the added person are returned if the operation is successful and if not, null. Value for the field <i>id</i> is not given as a parameter. Generating an id is better left for the server.
620611

621-
622612
Mutations also require a resolver:
623613

624614
```js
@@ -707,14 +697,13 @@ If we try to create a new person, but the parameters do not correspond with the
707697

708698
So some of the error handling can be automatically done with GraphQL [validation](https://graphql.org/learn/validation/).
709699

710-
However, GraphQL cannot handle everything automatically. For example, stricter rules for data sent to a Mutation have to be added manually.
711-
The errors from those rules are handled by [the error handling mechanism of Apollo Server](https://www.apollographql.com/docs/apollo-server/data/errors).
700+
However, GraphQL cannot handle everything automatically. For example, stricter rules for data sent to a Mutation have to be added manually. An error could be handeled by throwing [GraphQLError](https://www.apollographql.com/docs/apollo-server/data/errors/#custom-errors) with a proper
701+
[error code](https://www.apollographql.com/docs/apollo-server/data/errors/#built-in-error-codes).
712702

713-
714-
Let's block adding the same name to the phonebook multiple times:
703+
Let's prevent adding the same name to the phonebook multiple times:
715704

716705
```js
717-
const { ApolloServer, UserInputError, gql } = require('@apollo/server') // highlight-line
706+
const { GraphQLError } = require('graphql') // highlight-line
718707

719708
// ...
720709

@@ -724,8 +713,11 @@ const resolvers = {
724713
addPerson: (root, args) => {
725714
// highlight-start
726715
if (persons.find(p => p.name === args.name)) {
727-
throw new UserInputError('Name must be unique', {
728-
invalidArgs: args.name,
716+
throw new GraphQLError('Name must be unique', {
717+
extensions: {
718+
code: 'BAD_USER_INPUT',
719+
invalidArgs: args.name
720+
}
729721
})
730722
}
731723
// highlight-end
@@ -739,9 +731,9 @@ const resolvers = {
739731
```
740732

741733

742-
So if the name to be added already exists in the phonebook, throw _UserInputError_ error.
734+
So if the name to be added already exists in the phonebook, throw _GraphQLError_ error.
743735

744-
![](../../images/8/6x.png)
736+
![](../../images/8/6new.png)
745737

746738
The current code of the application can be found on [GitHub](https://github.com/fullstack-hy2020/graphql-phonebook-backend/tree/part8-2), branch <i>part8-2</i>.
747739

@@ -933,12 +925,6 @@ In some cases, it might be beneficial to name the queries. This is the case espe
933925
Through the exercises, we will implement a GraphQL backend for a small library.
934926
Start with [this file](https://github.com/fullstack-hy2020/misc/blob/master/library-backend.js). Remember to _npm init_ and to install dependencies!
935927

936-
**Note** at the time of writing (10th Dec 2022) the code used in this part is not fully compatible with the new version of the Apollo Server, and because of this, if you want everything to work smoothly you should install the version _3.10.1_:
937-
938-
```bash
939-
npm install [email protected] graphql
940-
```
941-
942928
Note also that the code does not initially work since the schema definition is not complete.
943929

944930
#### 8.1: The number of books and authors

src/content/8/en/part8b.md

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,11 @@ We'll start with the following code for our application:
3535
import ReactDOM from 'react-dom/client'
3636
import App from './App'
3737

38-
import { ApolloClient, HttpLink, InMemoryCache, gql } from '@apollo/client'
38+
import { ApolloClient, InMemoryCache, gql } from '@apollo/client'
3939

4040
const client = new ApolloClient({
41+
uri: 'http://localhost:4000',
4142
cache: new InMemoryCache(),
42-
link: new HttpLink({
43-
uri: 'http://localhost:4000',
44-
})
4543
})
4644

4745
const query = gql`
@@ -89,15 +87,12 @@ import App from './App'
8987
import {
9088
ApolloClient,
9189
ApolloProvider, // highlight-line
92-
HttpLink,
9390
InMemoryCache,
9491
} from '@apollo/client'
9592

9693
const client = new ApolloClient({
94+
uri: 'http://localhost:4000',
9795
cache: new InMemoryCache(),
98-
link: new HttpLink({
99-
uri: 'http://localhost:4000',
100-
}),
10196
})
10297

10398
ReactDOM.createRoot(document.getElementById('root')).render(
@@ -750,8 +745,6 @@ It looks bleak, but it works:
750745
Surprisingly, when a person's number is changed, the new number automatically appears on the list of persons rendered by the <i>Persons</i> component.
751746
This happens because each person has an identifying field of type <i>ID</i>, so the person's details saved to the cache update automatically when they are changed with the mutation.
752747
753-
The current code of the application can be found on [GitHub](https://github.com/fullstack-hy2020/graphql-phonebook-frontend/tree/part8-4) branch <i>part8-4</i>.
754-
755748
Our application still has one small flaw. If we try to change the phone number for a name which does not exist, nothing seems to happen.
756749
This happens because if a person with the given name cannot be found,
757750
the mutation response is <i>null</i>:
@@ -820,7 +813,7 @@ useEffect(() => {
820813
821814
However, this solution does not work if the _notify_ function is not wrapped to a [useCallback](https://reactjs.org/docs/hooks-reference.html#usecallback) function. If it's not, this results in an endless loop. When the _App_ component is rerendered after a notification is removed, a <i>new version</i> of _notify_ gets created which causes the effect function to be executed, which causes a new notification, and so on, and so on...
822815
823-
The current code of the application can be found on [GitHub](https://github.com/fullstack-hy2020/graphql-phonebook-frontend/tree/part8-5) branch <i>part8-5</i>.
816+
The current code of the application can be found on [GitHub](https://github.com/fullstack-hy2020/graphql-phonebook-frontend/tree/part8-4) branch <i>part8-4</i>.
824817
825818
### Apollo Client and the applications state
826819

src/content/8/fi/osa8a.md

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -245,15 +245,14 @@ Toteutetaan nyt GraphQL-palvelin tämän hetken johtavaa kirjastoa [Apollo Serve
245245
Luodaan uusi npm-projekti komennolla _npm init_ ja asennetaan tarvittavat riippuvuudet
246246

247247
```bash
248-
npm install apollo-server@3.10.1 graphql
248+
npm install @apollo/server graphql
249249
```
250250

251-
**Huom:** tätä kirjoittaessa (10.12.2022) tämän osan koodi ei ole täysin yhteensopivaa uusimman Apollo Serverin version kanssa. Tämän takia kannattaa asentaa versio _3.10.1_ jos haluat että koodi toimii sellaisenaan. Osa päivitetään vuoden 2023 alkupuolella.
252-
253251
Alustava toteutus on seuraavassa
254252

255253
```js
256-
const { ApolloServer, gql } = require('apollo-server')
254+
const { ApolloServer } = require('@apollo/server')
255+
const { startStandaloneServer } = require('@apollo/server/standalone')
257256

258257
let persons = [
259258
{
@@ -278,7 +277,7 @@ let persons = [
278277
},
279278
]
280279

281-
const typeDefs = gql`
280+
const typeDefs = `
282281
type Person {
283282
name: String!
284283
phone: String
@@ -308,12 +307,14 @@ const server = new ApolloServer({
308307
resolvers,
309308
})
310309

311-
server.listen().then(({ url }) => {
310+
startStandaloneServer(server, {
311+
listen: { port: 4000 },
312+
}).then(({ url }) => {
312313
console.log(`Server ready at ${url}`)
313314
})
314315
```
315316

316-
Toteutuksen ytimessä on _ApolloServer_, joka saa kaksi parametria
317+
Toteutuksen ytimessä on [ApolloServer](https://www.apollographql.com/docs/apollo-server/api/apollo-server/), joka saa kaksi parametria
317318

318319
```js
319320
const server = new ApolloServer({
@@ -324,7 +325,7 @@ const server = new ApolloServer({
324325

325326
parametreista ensimmäinen _typeDefs_ sisältää sovelluksen käyttämän GraphQL-skeeman.
326327

327-
Toinen parametri on olio, joka sisältää palvelimen [resolverit](https://www.apollographql.com/docs/apollo-server/data/data/#resolver-map), eli käytännössä koodin, joka määrittelee <i>miten</i> GraphQL-kyselyihin vastataan.
328+
Toinen parametri on olio, joka sisältää palvelimen [resolverit](https://www.apollographql.com/docs/apollo-server/data/resolvers/), eli käytännössä koodin, joka määrittelee <i>miten</i> GraphQL-kyselyihin vastataan.
328329

329330
Resolverien koodi on seuraavassa:
330331

@@ -698,12 +699,12 @@ Jos yritämme luoda uuden henkilön, mutta parametrit eivät vastaa skeemassa m
698699

699700
GraphQL:n [validoinnin](https://graphql.org/learn/validation/) avulla pystytään siis jo automaattisesti hoitamaan osa virheenkäsittelyä.
700701

701-
Kaikkea GraphQL ei kuitenkaan pysty hoitamaan automaattisesti. Esimerkiksi tarkemmat säännöt mutaatiolla lisättävän datan kenttien muodolle on lisättävä itse. Niistä aiheutuvat virheet tulee hoitaa [GraphQL:n poikkeuskäsittelymekanismilla](https://www.apollographql.com/docs/apollo-server/data/errors/).
702+
Kaikkea GraphQL ei kuitenkaan pysty hoitamaan automaattisesti. Esimerkiksi tarkemmat säännöt mutaatiolla lisättävän datan kenttien muodolle on lisättävä itse. Niistä aiheutuvat virheet tulee hoitaa itse heittämällä sopivalla [virhekoodilla](https://www.apollographql.com/docs/apollo-server/data/errors/#built-in-error-codes) varustetu [GraphQLError](https://www.apollographql.com/docs/apollo-server/data/errors/#custom-errors).
702703

703704
Estetään saman nimen lisääminen puhelinluetteloon useampaan kertaan:
704705

705706
```js
706-
const { ApolloServer, UserInputError, gql } = require('apollo-server') // highlight-line
707+
const { GraphQLError } = require('graphql') // highlight-line
707708

708709
// ...
709710

@@ -713,8 +714,11 @@ const resolvers = {
713714
addPerson: (root, args) => {
714715
// highlight-start
715716
if (persons.find(p => p.name === args.name)) {
716-
throw new UserInputError('Name must be unique', {
717-
invalidArgs: args.name,
717+
throw new GraphQLError('Name must be unique', {
718+
extensions: {
719+
code: 'BAD_USER_INPUT',
720+
invalidArgs: args.name
721+
}
718722
})
719723
}
720724
// highlight-end
@@ -727,9 +731,9 @@ const resolvers = {
727731
}
728732
```
729733

730-
Eli jos lisättävä nimi on jo luettelossa heitetään poikkeus _UserInputError_.
734+
Eli jos lisättävä nimi on jo luettelossa heitetään poikkeus _GraphQLError_.
731735

732-
![](../../images/8/6x.png)
736+
![](../../images/8/6new.png)
733737

734738
Sovelluksen tämänhetkinen koodi on kokonaisuudessaan [GitHubissa](https://github.com/fullstack-hy2020/graphql-phonebook-backend/tree/part8-2), branchissa <i>part8-2</i>.
735739

@@ -921,13 +925,6 @@ Tehtävissä toteutetaan yksinkertaisen kirjaston GraphQL:ää tarjoava backend.
921925

922926
Huomaa, että koodin käynnistäminen aiheuttaa alussa virheen, sillä skeeman määrittely on puutteellinen.
923927

924-
**Huom:** tätä kirjoittaessa (10.12.2022) tämän osan koodi ei ole täysin yhteensopivaa uusimman Apollo Serverin version kanssa. Tämän takia kannattaa asentaa versio _3.10.1_ jos haluat että koodi toimii sellaisenaan. Osa päivitetään vuoden 2023 alkupuolella.
925-
926-
Asenna siis riippuvuudet seuraavasti:
927-
928-
```bash
929-
npm install [email protected] graphql
930-
```
931928
#### 8.1: kirjojen ja kirjailijoiden määrä
932929

933930
Toteuta kyselyt _bookCount_ ja _authorCount_ jotka palauttavat kirjojen ja kirjailijoiden lukumäärän.

0 commit comments

Comments
 (0)