Motivation
Now we’d like to write a data scheme and let Apollo generate the Angular Code for us [1]
Drafting
No matter from which direction we are coming (backend first, frontend first, any mocking server), we’d need a GraphQL Scheme. There are several specialized GraphQL IDEs, coming from [2], let’s try this sandbox https://graphql.org/swapi-graphql together with a cheat sheet [3].
Remeber, we wanted to write kind of a Todo App, now we have to roll-out a central data model of it. Remember also, we wanted to start simple.
After 30mins of chilling I came up with an idea: we got articles, they have tags, an article contains certain types of paragraphs, say text, forumlas and snippets – any of them encoded as string. We’d like to do typical CRUD operations on any of them.
We might also want to install the vs-code graphql extension: https://www.apollographql.com/docs/devtools/editor-plugins/
After looking some samples and get into the scheme description [4], I created the following definition, where the Type Query defines read operations and the type Mutation defines writes. Store this file in the top directory of your project as:
schema.graphql
enum ParagraphType { PlainText, Snippet, Formula } "This is a tag" type Tag { name : String } "This is a paragraph" type Paragraph { id: String! type: ParagraphType! content: String! } "This is a section" type Section { id: String! name: String tags: [Tag!] subsections: [Section!] paragraphs: [Paragraph!] } type Query { getSections: [Section] getTags: [Tag] } type Mutation { addSection(sectionId: String!, name: String!) : Section addParagraph(sectionId: String!, type: ParagraphType!, content: String!) : Paragraph addTag(sectionId: String!, name : String!) : Tag removeSection(sectionId : String!) : Section removeParagraph(paragaphId : String!) : Paragraph removeTag(name : String!) : Tag } schema { query : Query mutation : Mutation }
Code generation
- Now we are in the position to create TypeScript types
- This shows, how we’d like to generate our code: https://graphql-code-generator.com/ we’ll follow the getting-started setup
- npm install -g @graphql-codegen/cli
(I had to downgrade an „is-promise“ package there from 2..2.0 to 2.1.0, to get it work) - call graphql-codegen init
- Ideally we get a menu now, select „Application with Angular“, type „../schema.graphql“, output to „src/app/generated/graphql.ts“, no introspection file, and „codegen“ for the script name
- Now run npm install and npm run codegen
- We observe: „Unable to find any GraphQL type definitions“ whoopsie.
- Let’s create a file called queries.graphql anywhere below src, we choose the directory „src/app/main-page“ here
query listSections {
getSections {
id
name
}
}
- npm run codegen again
- we got a new file src/app/generated/graphql.ts – have a look
- to avoid committing this via git, add the line /src/app/generated to .gitignore file – because we won’t commit generated files
- now we want to consume this:
main-page.component.ts
import { Component, OnInit } from '@angular/core'; import { Observable } from 'rxjs'; import { flatMap } from 'rxjs/operators'; import { Section, ListSectionsGQL } from '../generated/graphql'; @Component({ selector: 'app-main-page', templateUrl: './main-page.component.html', styleUrls: ['./main-page.component.scss'], }) export class MainPageComponent implements OnInit { sections: Observable<Section>; // Dependency Injection of GQL constructor(private gql: ListSectionsGQL) {} ngOnInit() { this.sections = this.gql .watch() .valueChanges.pipe(flatMap((result) => result.data.getSections)); } }
main-page.component.html
<div class="container"> <h2>Rates</h2> <ul class="list-group"> <li *ngFor="let section of sections | async" class="list-group-item"> {{section.name}} </li> </ul> </div>
Observations
- compile & run
- we used dependency injection to retrieve a type safe result for now
- the result list is empty – well, we actually do not have a server, producing this data yet
- the network calls would be a first candidate for refactoring / introducing an architecture, which „binds“ query and ui more directly
- perform a git commit