Skip to content

Commit 49b5078

Browse files
committed
tutorial wip
1 parent 96106a6 commit 49b5078

File tree

1 file changed

+109
-71
lines changed

1 file changed

+109
-71
lines changed

content/blog/getting-started-with-spring-boot.md

Lines changed: 109 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ title = "Getting started with GraphQL Java and Spring Boot"
33
author = "Andreas Marek"
44
tags = []
55
categories = []
6-
date = 2018-10-22T01:00:00+10:00
6+
date = 2019-01-23
77
toc = "true"
88
+++
99

@@ -18,9 +18,9 @@ For example we wanna query the details for specific book from a online store bac
1818

1919
With GraphQL you send the following query to server to get the details for the book with the id "123":
2020

21-
{{< highlight graphql "linenos=table" >}}
21+
{{< highlight scala "linenos=table" >}}
2222
{
23-
book(id: "123"){
23+
bookById(id: "123"){
2424
id
2525
name
2626
pageCount
@@ -32,17 +32,20 @@ With GraphQL you send the following query to server to get the details for the b
3232
}
3333
{{< / highlight >}}
3434

35-
This is not JSON (even if it looks remotely similar), but it is a GraphQL query.
35+
This is not JSON (even if it looks remotely similar), it is a GraphQL query.
3636

3737
But the response is normal JSON:
3838
{{< highlight json "linenos=table" >}}
39-
{
40-
"id":"123",
41-
"name":"Harry Potter and the Philosopher's Stone",
42-
"pageCount":223,
43-
"author": {
44-
"firstName":"J. K.",
45-
"lastName":"Rowling"
39+
{
40+
"bookById":
41+
{
42+
"id":"123",
43+
"name":"Harry Potter and the Philosopher's Stone",
44+
"pageCount":223,
45+
"author": {
46+
"firstName":"J. K.",
47+
"lastName":"Rowling"
48+
}
4649
}
4750
}
4851
{{< / highlight >}}
@@ -51,62 +54,45 @@ One very important property of GraphQL is that it is statically typed: the serve
5154

5255
The schema for the above query looks like this:
5356

54-
{{< highlight graphql "linenos=table" >}}
57+
{{< highlight scala "linenos=table" >}}
5558
type Query {
56-
book(id: ID): Book
59+
bookById(id: ID): Book
5760
}
5861

5962
type Book {
6063
id: ID
6164
name: String
6265
pageCount: Int
63-
author: Person
66+
author: Author
6467
}
6568

66-
type Person {
69+
type Author {
70+
id: ID
6771
firstName: String
6872
lastName: String
6973
}
7074
{{< / highlight >}}
7175

72-
This tutorial will focus on how to implement a GraphQL server in Java.
76+
This tutorial will focus on how to implement a GraphQL server with schema in Java.
7377

7478
We barely touched GraphQL. Further information can be found on the official page: https://graphql.github.io/learn/
7579

76-
7780
# GraphQL Java Overview
7881

7982
[GraphQL Java](https://www.graphql-java.com) is the Java (server) implementation for GraphQL.
8083
The are several repositories in the GraphQL Java Github org. The most important one is the [GraphQL Java Engine](https://github.com/graphql-java/graphql-java) which is basis for everything else.
8184

82-
We will also use the [GraphQL Java Spring Boot](https://github.com/graphql-java/graphql-java-spring) adapter, which takes care of exposing your GraphQL API via HTTP.
83-
84-
GraphQL Java itself is only concerned with executing queries. It doesn't deal with any HTTP or JSON related topics. For these aspects we will use [Spring Boot](https://spring.io/projects/spring-boot).
85+
GraphQL Java Engine itself is only concerned with executing queries. It doesn't deal with any HTTP or JSON related topics. For these aspects we will use the [GraphQL Java Spring Boot](https://github.com/graphql-java/graphql-java-spring) adapter which takes care of exposing our API via Spring Boot over HTTP.
8586

8687
The main steps of creating a GraphQL Java server are:
8788

8889
1. Defining a GraphQL Schema.
8990
2. Defining on how the actual data for a query is fetched.
9091

91-
9292
# Our example API: getting book details
9393

94-
Our example app we will build is a simple online store for books.
95-
We assume the very simple user flow:
96-
97-
the user comes to our page and sees all available books for order.
98-
They can select a specific book and look up the details. If they like it they can order it.
99-
100-
We will build a GraphQL server which will cover the following use cases:
101-
102-
1. get a list of available books
103-
1. get specific book details
104-
105-
We will incrementally build our app.
106-
107-
> **What about the schema/API design?**<br/>
108-
Schema and API design itself is interesting and challenging but we will focus on implementing the server and not discuss the actual schema design choices.
109-
94+
Our example app will be a simple API to get details for a specific book.
95+
This is in no way a comprehensive API, but it is enough for this tutorial.
11096

11197
# Create a Spring Boot app
11298

@@ -121,7 +107,7 @@ Select:
121107
For the project metadata we use:
122108

123109
- Group: `com.graphql-java.tutorial`
124-
- Artifact: `online-store`
110+
- Artifact: `book-details`
125111

126112
As dependency we just select `Web`.
127113

@@ -132,90 +118,142 @@ We are adding three dependencies to our project inside the `dependencies` sectio
132118

133119
the first two are GraphQL Java and GraphQL Java Spring and then we also add [Google Guava](https://github.com/google/guava). Guava is not strictly needed but it will make our life a little bit easier.
134120

121+
The dependencies will look like that:
122+
135123
{{< highlight groovy "linenos=table" >}}
136124
dependencies {
137-
...
138-
implementation('com.graphql-java:graphql-java:11.0')
139-
implementation "com.graphql-java:graphql-java-spring-boot-starter-webmvc:1.0"
140-
implementation('com.google.guava:guava:26.0-jre')
125+
implementation 'com.graphql-java:graphql-java:11.0' // NEW
126+
implementation 'com.graphql-java:graphql-java-spring-boot-starter-webmvc:1.0' // NEW
127+
implementation 'com.google.guava:guava:26.0-jre' // NEW
128+
implementation 'org.springframework.boot:spring-boot-starter-web'
129+
testImplementation 'org.springframework.boot:spring-boot-starter-test'
141130
}
142131
{{< / highlight >}}
143132

144-
# Defining the schema
133+
# Schema
145134

146135
We are creating a new file `schema.graphqls` in `src/main/resources` with the following content:
147136

148-
{{< highlight graphql "linenos=table" >}}
137+
{{< highlight scala "linenos=table" >}}
149138
type Query {
150-
books: [Books]
151-
bookById(id: ID!): Book
139+
bookById(id: ID): Book
152140
}
153141

154142
type Book {
155143
id: ID
156144
name: String
145+
pageCount: Int
146+
author: Author
157147
}
158148

149+
type Author {
150+
id: ID
151+
firstName: String
152+
lastName: String
153+
}
159154
{{< / highlight >}}
155+
<p/>
160156

161-
This schema defines two top level fields (fields in the type `Query`): `books` which results in a list of `Book`s and a `bookById` to query a specific Book by id.
157+
This schema defines one top level field (field in the type `Query`): `bookById` which returns the details of a specific book.
162158

163-
It also defines the type `Book` which has two fields: `id` and `name`.
159+
It also defines the type `Book` which has the fields: `id`, `name`, `pageCount` and `author`.
160+
`author` is of type `Author`, which is defined after `Book`.
164161

165162
> The Domain Specific Language shown above which is used to describe a schema is called Schema Definition Language or SDL.
166163
167164
But so far it is just a normal text. We need to "bring it to live" by reading the file and parsing it.
168-
We are using Guava to read the file at runtime from our classpath:
165+
166+
We are creating a new `GraphQLProvider` class in the package `com.graphqljava.tutorial.bookdetails` with an `init` method which will create a `GraphQL` instance:
169167

170168
{{< highlight java "linenos=table" >}}
171-
URL url = Resources.getResource("schema.graphql");
172-
String sdl = Resources.toString(url, Charsets.UTF_8);
169+
170+
@Component
171+
public class GraphQLProvider {
172+
173+
private GraphQL graphQL;
174+
175+
@Bean
176+
public GraphQL graphQL() {
177+
return graphQL;
178+
}
179+
180+
@PostConstruct
181+
public void init() throws IOException {
182+
URL url = Resources.getResource("schema.graphqls");
183+
String sdl = Resources.toString(url, Charsets.UTF_8);
184+
GraphQLSchema graphQLSchema = buildSchema(sdl);
185+
this.graphQL = GraphQL.newGraphQL(graphQLSchema).build();
186+
}
187+
188+
private GraphQLSchema buildSchema(String sdl) {
189+
//TODO
190+
}
191+
}
173192
{{< / highlight >}}
193+
<p/>
194+
195+
196+
We are using Guava to read the file at runtime from our classpath, then create a `GraphQLSchema` and `GraphQL` instance. This `GraphQL` instance is exposed as Spring Bean. The GraphQL Java Spring adapter will use that `GraphQL` instance to expose it the schema over HTTP on the default url `/graphql`.
174197

175-
We now using GraphQL Java for the first time: We are transforming the `sdl` into a `TypeDefinitionRegistry`:
176198

199+
What we still need to do is to implement the `buildSchema` method which creates the `GraphQLSchema` instance:
177200

178201
{{< highlight java "linenos=table" >}}
179-
TypeDefinitionRegistry typeRegistry = new SchemaParser().parse(sdl);
202+
@Autowired
203+
GraphQLDataFetchers graphQLDataFetchers;
204+
205+
private GraphQLSchema buildSchema(String sdl) {
206+
TypeDefinitionRegistry typeRegistry = new SchemaParser().parse(sdl);
207+
RuntimeWiring runtimeWiring = buildWiring();
208+
SchemaGenerator schemaGenerator = new SchemaGenerator();
209+
return schemaGenerator.makeExecutableSchema(typeRegistry, runtimeWiring);
210+
}
211+
212+
private RuntimeWiring buildWiring() {
213+
return RuntimeWiring.newRuntimeWiring()
214+
.type(newTypeWiring("Query")
215+
.dataFetcher("bookById", graphQLDataFetchers.getBookByIdDataFetcher()))
216+
.type(newTypeWiring("Book")
217+
.dataFetcher("author", graphQLDataFetchers.getAuthorDataFetcher())
218+
.build())
219+
.build();
220+
}
180221
{{< / highlight >}}
222+
<p/>
181223

182-
This `TypeDefinitionRegistry` is just a parsed version of the schema definition file.
224+
`TypeDefinitionRegistry` is the parsed version of our schema file. `SchemaGenerator` combines the `TypeDefinitionRegistry` with `RuntimeWiring` to actually make the `GraphQLSchema`.
183225

184-
## Creating a GraphQLSchema
226+
`buildRuntimeWiring` uses the `graphQLDataFetchers` bean to actually register two `DataFetcher`:
185227

186-
The `typeRegistry` defined above is just types: it describes how the schema looks like, but not how it actually works when a query is executed.
228+
- One to retrieve a book with a specific ID
229+
- One to get the author for a specific book.
187230

231+
`DataFetcher` and how to implement the `GraphQLDataFetcher` bean is explained in the next section.
188232

189233
# DataFetchers
190234

191235
Probably the most important concept for a GraphQL Java server is a `DataFetcher`:
192236
A `DataFetcher` fetches the Data for one field while the query is executed.
193237

194238
While GraphQL Java is executing a query it calls the appropriate `DataFetcher` for each field it encounters in query.
195-
A `DataFetcher` is a Interface with a single method, taking a single argument of type `DataFetcherEnvironment`.
239+
A `DataFetcher` is an Interface with a single method, taking a single argument of type `DataFetcherEnvironment`:
196240

197-
For our first iteration we are doing the simplest possible thing that works: we are fetching the books we wanna display from in-memory.
198-
199-
Our code looks like this:
200241

201242
{{< highlight java "linenos=table" >}}
202-
243+
public interface DataFetcher<T> {
244+
T get(DataFetchingEnvironment dataFetchingEnvironment) throws Exception;
245+
}
203246
{{< / highlight >}}
247+
<p/>
204248

249+
Important: **Every** field from the schema has a `DataFetcher` associated with. If you don't specify any `DataFetcher` for a specific field the default `PropertyDataFetcher` is used.
205250

206-
Important: **Every** field from the schema has a `DataFetcher` associated with. Most of them have the a default `DataFetcher` of type `PropertyDataFetcher`.
207-
208-
# Exposing the schema via HTTP
209-
210-
The last step is to actually expose the GraphQL schema via HTTP. This is done via the GraphQL Java Spring adapter.
251+
We are creating a new class `GraphQLDataFetchers
211252

212-
The only thing you have todo is to actually define a `Bean` of type `GraphQL` in you Spring Boot app.
213253

214254

215-
{{< highlight java "linenos=table" >}}
216-
217-
{{< / highlight >}}
255+
# Testing the API
218256

219257

220-
# Full source code
258+
# Complete example source code
221259

0 commit comments

Comments
 (0)