Skip to content

Commit c16521c

Browse files
committed
Move interception code snippets to Java classes
This commit starts movint code snippets from the reference documentation to actual Java classes so that they're compiled and checked at build time.
1 parent 3d1f3b2 commit c16521c

File tree

6 files changed

+219
-94
lines changed

6 files changed

+219
-94
lines changed

spring-graphql-docs/src/docs/asciidoc/index.adoc

Lines changed: 4 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -117,29 +117,7 @@ handled as `request-stream`.
117117
`GraphQlRSocketHandler` can be used a delegate from an `@Controller` that is mapped to
118118
the route for GraphQL requests. For example:
119119

120-
[source,java,indent=0,subs="verbatim,quotes"]
121-
----
122-
@Controller
123-
public class GraphQlRSocketController {
124-
125-
private final GraphQlRSocketHandler handler;
126-
127-
GraphQlRSocketController(GraphQlRSocketHandler handler) {
128-
this.handler = handler;
129-
}
130-
131-
@MessageMapping("graphql")
132-
public Mono<Map<String, Object>> handle(Map<String, Object> payload) {
133-
return this.handler.handle(payload);
134-
}
135-
136-
@MessageMapping("graphql")
137-
public Flux<Map<String, Object>> handleSubscription(Map<String, Object> payload) {
138-
return this.handler.handleSubscription(payload);
139-
}
140-
}
141-
----
142-
120+
include::code:GraphQlRSocketController[]
143121

144122

145123

@@ -166,89 +144,21 @@ incoming requests and do one of the following:
166144

167145
For example, an interceptor can pass an HTTP request header to a `DataFetcher`:
168146

169-
[source,java,indent=0,subs="verbatim,quotes"]
170-
----
171-
class HeaderInterceptor implements WebGraphQlInterceptor { <1>
172-
173-
@Override
174-
public Mono<WebGraphQlResponse> intercept(WebGraphQlRequest request, Chain chain) {
175-
String value = request.getHeaders().getFirst("myHeader");
176-
request.configureExecutionInput((executionInput, builder) ->
177-
builder.graphQLContext(Collections.singletonMap("myHeader", value)).build());
178-
return chain.next(request);
179-
}
180-
}
181-
182-
@Controller
183-
class MyController { <2>
184-
185-
@QueryMapping
186-
Person person(@ContextValue String myHeader) {
187-
// ...
188-
}
189-
}
190-
----
147+
include::code:RequestHeaderInterceptor[]
191148
<1> Interceptor adds HTTP request header value into GraphQLContext
192149
<2> Data controller method accesses the value
193150

194151
Reversely, an interceptor can access values added to the `GraphQLContext` by a controller:
195152

196-
[source,java,indent=0,subs="verbatim,quotes"]
197-
----
198-
@Controller
199-
class MyController {
200-
201-
@QueryMapping
202-
Person person(GraphQLContext context) { <1>
203-
context.put("cookieName", "123");
204-
}
205-
}
206-
207-
// Subsequent access from a WebGraphQlInterceptor
208-
209-
class HeaderInterceptor implements WebGraphQlInterceptor {
210-
211-
@Override
212-
public Mono<WebGraphQlResponse> intercept(WebGraphQlRequest request, Chain chain) { <2>
213-
return chain.next(request).doOnNext(response -> {
214-
String value = response.getExecutionInput().getGraphQLContext().get("cookieName");
215-
ResponseCookie cookie = ResponseCookie.from("cookieName", value).build();
216-
response.getResponseHeaders().add(HttpHeaders.SET_COOKIE, cookie.toString());
217-
});
218-
}
219-
}
220-
----
153+
include::code:ResponseHeaderInterceptor[]
221154
<1> Controller adds value to the `GraphQLContext`
222155
<2> Interceptor uses the value to add an HTTP response header
223156

224157
`WebGraphQlHandler` can modify the `ExecutionResult`, for example, to inspect and modify
225158
request validation errors that are raised before execution begins and which cannot be
226159
handled with a `DataFetcherExceptionResolver`:
227160

228-
[source,java,indent=0,subs="verbatim,quotes"]
229-
----
230-
static class RequestErrorInterceptor implements WebGraphQlInterceptor {
231-
232-
@Override
233-
public Mono<WebGraphQlResponse> intercept(WebGraphQlRequest request, Chain chain) {
234-
return chain.next(request).map(response -> {
235-
if (response.isValid()) {
236-
return response; <1>
237-
}
238-
239-
List<GraphQLError> errors = response.getErrors().stream() <2>
240-
.map(error -> {
241-
GraphqlErrorBuilder<?> builder = GraphqlErrorBuilder.newError();
242-
// ...
243-
return builder.build();
244-
})
245-
.collect(Collectors.toList());
246-
247-
return response.transform(builder -> builder.errors(errors).build()); <3>
248-
});
249-
}
250-
}
251-
----
161+
include::code:RequestErrorInterceptor[]
252162
<1> Return the same if `ExecutionResult` has a "data" key with non-null value
253163
<2> Check and transform the GraphQL errors
254164
<3> Update the `ExecutionResult` with the modified errors
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Copyright 2020-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.graphql.docs.server.interception.web;
18+
19+
public record Person(String firstName, String lastName) {
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright 2020-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.graphql.docs.server.interception.web;
18+
19+
import java.util.List;
20+
21+
import graphql.GraphQLError;
22+
import graphql.GraphqlErrorBuilder;
23+
import reactor.core.publisher.Mono;
24+
25+
import org.springframework.graphql.server.WebGraphQlInterceptor;
26+
import org.springframework.graphql.server.WebGraphQlRequest;
27+
import org.springframework.graphql.server.WebGraphQlResponse;
28+
29+
class RequestErrorInterceptor implements WebGraphQlInterceptor {
30+
31+
@Override
32+
public Mono<WebGraphQlResponse> intercept(WebGraphQlRequest request, Chain chain) {
33+
return chain.next(request).map(response -> {
34+
if (response.isValid()) {
35+
return response; // <1>
36+
}
37+
38+
List<GraphQLError> errors = response.getErrors().stream() // <2>
39+
.map(error -> {
40+
GraphqlErrorBuilder<?> builder = GraphqlErrorBuilder.newError();
41+
// ...
42+
return builder.build();
43+
})
44+
.toList();
45+
46+
return response.transform(builder -> builder.errors(errors).build()); // <3>
47+
});
48+
}
49+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright 2020-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.graphql.docs.server.interception.web;
18+
19+
import java.util.Collections;
20+
21+
import reactor.core.publisher.Mono;
22+
23+
import org.springframework.graphql.data.method.annotation.ContextValue;
24+
import org.springframework.graphql.data.method.annotation.QueryMapping;
25+
import org.springframework.graphql.server.WebGraphQlInterceptor;
26+
import org.springframework.graphql.server.WebGraphQlRequest;
27+
import org.springframework.graphql.server.WebGraphQlResponse;
28+
import org.springframework.stereotype.Controller;
29+
30+
class RequestHeaderInterceptor implements WebGraphQlInterceptor { // <1>
31+
32+
@Override
33+
public Mono<WebGraphQlResponse> intercept(WebGraphQlRequest request, Chain chain) {
34+
String value = request.getHeaders().getFirst("myHeader");
35+
request.configureExecutionInput((executionInput, builder) ->
36+
builder.graphQLContext(Collections.singletonMap("myHeader", value)).build());
37+
return chain.next(request);
38+
}
39+
}
40+
41+
@Controller
42+
class MyContextValueController { // <2>
43+
44+
@QueryMapping
45+
Person person(@ContextValue String myHeader) {
46+
/**/ return new Person("spring", "graphql");
47+
}
48+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright 2020-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.graphql.docs.server.interception.web;
18+
19+
import graphql.GraphQLContext;
20+
import reactor.core.publisher.Mono;
21+
22+
import org.springframework.graphql.data.method.annotation.QueryMapping;
23+
import org.springframework.graphql.server.WebGraphQlInterceptor;
24+
import org.springframework.graphql.server.WebGraphQlRequest;
25+
import org.springframework.graphql.server.WebGraphQlResponse;
26+
import org.springframework.http.HttpHeaders;
27+
import org.springframework.http.ResponseCookie;
28+
import org.springframework.stereotype.Controller;
29+
30+
// Subsequent access from a WebGraphQlInterceptor
31+
32+
class ResponseHeaderInterceptor implements WebGraphQlInterceptor {
33+
34+
@Override
35+
public Mono<WebGraphQlResponse> intercept(WebGraphQlRequest request, Chain chain) { // <2>
36+
return chain.next(request).doOnNext(response -> {
37+
String value = response.getExecutionInput().getGraphQLContext().get("cookieName");
38+
ResponseCookie cookie = ResponseCookie.from("cookieName", value).build();
39+
response.getResponseHeaders().add(HttpHeaders.SET_COOKIE, cookie.toString());
40+
});
41+
}
42+
}
43+
44+
@Controller
45+
class MyCookieController {
46+
47+
@QueryMapping
48+
Person person(GraphQLContext context) { // <1>
49+
context.put("cookieName", "123");
50+
/**/ return new Person("spring", "graphql");
51+
}
52+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2020-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.graphql.docs.server.transports.rsocket;
18+
19+
import java.util.Map;
20+
21+
import reactor.core.publisher.Flux;
22+
import reactor.core.publisher.Mono;
23+
24+
import org.springframework.graphql.server.GraphQlRSocketHandler;
25+
import org.springframework.messaging.handler.annotation.MessageMapping;
26+
import org.springframework.stereotype.Controller;
27+
28+
@Controller
29+
public class GraphQlRSocketController {
30+
31+
private final GraphQlRSocketHandler handler;
32+
33+
GraphQlRSocketController(GraphQlRSocketHandler handler) {
34+
this.handler = handler;
35+
}
36+
37+
@MessageMapping("graphql")
38+
public Mono<Map<String, Object>> handle(Map<String, Object> payload) {
39+
return this.handler.handle(payload);
40+
}
41+
42+
@MessageMapping("graphql")
43+
public Flux<Map<String, Object>> handleSubscription(Map<String, Object> payload) {
44+
return this.handler.handleSubscription(payload);
45+
}
46+
}

0 commit comments

Comments
 (0)