spring-graphql.md 64.0 KB
Newer Older
茶陵後's avatar
茶陵後 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528
# Spring for GraphQL Documentation

## 1. Overview

Spring for GraphQL provides support for Spring applications built on[GraphQL Java](https://www.graphql-java.com/). It is a joint collaboration between both
teams. Our shared philosophy is to be less opinionated and more focused on
comprehensive and wide-ranging support.

Spring for GraphQL is the successor of the[GraphQL Java Spring](https://github.com/graphql-java/graphql-java-spring) project from
the GraphQL Java team. It aims to be the foundation for all Spring, GraphQL applications.

The project is in a milestone phase towards a 1.0 release, currently, and looking for
feedback. Please, use our[issue tracker](https://github.com/spring-projects/spring-graphql/issues) to report a
problem, discuss a design issue, or request a feature.

To get started, check the Spring GraphQL starter on [start.spring.io](https://start.spring.io) and the[Samples](#samples) sections.

## 2. Requirements

Spring for GraphQL requires the following as a baseline:

* JDK8

* Spring Framework 5.3

* GraphQL Java 17

* Spring Data 2021.1.0 or later for QueryDSL or Query by Example

## 3. Web Transports

Spring for GraphQL supports GraphQL requests over HTTP and over WebSocket.

### 3.1. HTTP

`GraphQlHttpHandler` handles GraphQL over HTTP requests and delegates to the[Web Interception](#web-interception) chain for request execution. There are two variants, one for
Spring MVC and one for Spring WebFlux. Both handle requests asynchronously and have
equivalent functionality, but rely on blocking vs non-blocking I/O respectively for
writing the HTTP response.

Requests must use HTTP POST with GraphQL request details included as JSON in the
request body, as defined in the proposed[GraphQL over HTTP](https://github.com/graphql/graphql-over-http/blob/main/spec/GraphQLOverHTTP.md)specification. Once the JSON body has been successfully decoded, the HTTP response
status is always 200 (OK), and any errors from GraphQL request execution appear in the
"errors" section of the GraphQL response.

`GraphQlHttpHandler` can be exposed as an HTTP endpoint by declaring a `RouterFunction`bean and using the `RouterFunctions` from Spring MVC or WebFlux to create the route. The
Boot starter does this, see the[Web Endpoints](https://docs.spring.io/spring-boot/docs/2.7.0-SNAPSHOT/reference/html/web.html#web.graphql.web-endpoints) section for
details, or check `GraphQlWebMvcAutoConfiguration` or `GraphQlWebFluxAutoConfiguration`it contains, for the actual config.

The Spring for GraphQL repository contains a Spring MVC[HTTP sample](https://github.com/spring-projects/spring-graphql/tree/main/samples/webmvc-http) application.

### 3.2. WebSocket

`GraphQlWebSocketHandler` handles GraphQL over WebSocket requests based on the[protocol](https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md) defined in the[graphql-ws](https://github.com/enisdenjo/graphql-ws) library. The main reason to use
GraphQL over WebSocket is subscriptions which allow sending a stream of GraphQL
responses, but it can also be used for regular queries with a single response.
The handler delegates every request to the [Web Interception](#web-interception) chain for further
request execution.

|   |GraphQL Over WebSocket Protocols<br/><br/>There are two such protocols, one in the[subscriptions-transport-ws](https://github.com/apollographql/subscriptions-transport-ws)library and another in the[graphql-ws](https://github.com/enisdenjo/graphql-ws) library. The former is not active and<br/>succeeded by the latter. Read this[blog post](https://the-guild.dev/blog/graphql-over-websockets) for the history.|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

There are two variants of `GraphQlWebSocketHandler`, one for Spring MVC and one for
Spring WebFlux. Both handle requests asynchronously and have equivalent functionality.
The WebFlux handler also uses non-blocking I/O and back pressure to stream messages,
which works well since in GraphQL Java a subscription response is a Reactive Streams`Publisher`.

The `graphql-ws` project lists a number of[recipes](https://github.com/enisdenjo/graphql-ws#recipes) for client use.

`GraphQlWebSocketHandler` can be exposed as a WebSocket endpoint by declaring a`SimpleUrlHandlerMapping` bean and using it to map the handler to a URL path. The Boot
starter has options to enable this, see the[Web Endpoints](https://docs.spring.io/spring-boot/docs/2.7.0-SNAPSHOT/reference/html/web.html#web.graphql.web-endpoints) section for
details, or check `GraphQlWebMvcAutoConfiguration` or `GraphQlWebFluxAutoConfiguration`it contains, for the actual config.

The Spring for GraphQL repository contains a WebFlux[WebSocket sample](https://github.com/spring-projects/spring-graphql/tree/main/samples/webflux-websocket) application.

### 3.3. Web Interception

[HTTP](#web-http) and [WebSocket](#web-websocket) transport handlers delegate to a common Web
interception chain for request execution. The chain consists of a sequence of`WebInterceptor` components, followed by a `GraphQlService` that invokes the GraphQL
Java engine.

`WebInterceptor` is as a common contract to use in both Spring MVC and WebFlux
applications. Use it to intercept requests, inspect HTTP request headers, or to register a
transformation of the `graphql.ExecutionInput`:

```
class MyInterceptor implements WebInterceptor {

    @Override
    public Mono<WebOutput> intercept(WebInput webInput, WebInterceptorChain chain) {
        webInput.configureExecutionInput((executionInput, builder) -> {
            Map<String, Object> map = ... ;
            return builder.extensions(map).build();
        });
        return chain.next(webInput);
    }
}

```

Use `WebInterceptor` also to intercept responses, add HTTP response headers, or transform
the `graphql.ExecutionResult`:

```
class MyInterceptor implements WebInterceptor {

    @Override
    public Mono<WebOutput> intercept(WebInput webInput, WebInterceptorChain chain) {
        return chain.next(webInput)
                .map(webOutput -> {
                    Object data = webOutput.getData();
                    Object updatedData = ... ;
                    return webOutput.transform(builder -> builder.data(updatedData));
                });
    }
}

```

`WebGraphQlHandler` provides a builder to initialize the Web interception chain. After
you build the chain, you can use the resulting `WebGraphQlHandler` to initialize the HTTP
or WebSocket transport handlers. The Boot starter configures all this, see the[Web Endpoints](https://docs.spring.io/spring-boot/docs/2.7.0-SNAPSHOT/reference/html/web.html#web.graphql.web-endpoints) section for
details, or check `GraphQlWebMvcAutoConfiguration` or `GraphQlWebFluxAutoConfiguration`it contains, for the actual config.

## 4. Request Execution

`GraphQlService` is the main Spring abstraction to call GraphQL Java to execute
requests. Underlying transports, such as the [Web Transports](#web-transports), delegate to `GraphQlService` to
handle requests.

The main implementation, `ExecutionGraphQlService`, is a thin facade around the
invocation of `graphql.GraphQL`. It is configured with a `GraphQlSource` for access to
the `graphql.GraphQL` instance.

### 4.1. `GraphQLSource`

`GraphQlSource` is a core Spring abstraction for access to the`graphql.GraphQL` instance to use for request execution. It provides a builder API to
initialize GraphQL Java and build a `GraphQlSource`.

The default `GraphQlSource` builder, accessible via `GraphQlSource.builder()`, enables
support for [Reactive `DataFetcher`](#execution-reactive-datafetcher), [Context Propagation](#execution-context), and[Exception Resolution](#execution-exceptions).

The Spring Boot [starter](https://docs.spring.io/spring-boot/docs/2.7.0-SNAPSHOT/reference/html/web.html#web.graphql) initializes a`GraphQlSource` instance through the default `GraphQlSource.Builder` and also enables
the following:

* Load [schema files](#execution-graphqlsource-schema-resources) from a configurable location.

* Expose [properties](https://docs.spring.io/spring-boot/docs/2.7.0-SNAPSHOT/reference/html/application-properties.html#appendix.application-properties.web)that apply to `GraphQlSource.Builder`.

* Detect [`RuntimeWiringConfigurer`](#execution-graphqlsource-runtimewiring-configurer) beans.

* Detect [Instrumentation](https://www.graphql-java.com/documentation/instrumentation) beans for[GraphQL metrics](https://docs.spring.io/spring-boot/docs/2.7.0-SNAPSHOT/reference/html/actuator.html#actuator.metrics.supported.spring-graphql).

* Detect `DataFetcherExceptionResolver` beans for[exception resolution](#execution-exceptions).

* Detect `GraphQlSourceBuilderCustomizer` beans for any other customizations.

#### 4.1.1. Schema Resources

`GraphQlSource.Builder` can be configured with one or more `Resource` instances to be
parsed and merged together. That means schema files can be loaded from just about any
location.

By default, the Spring Boot starter[finds schema files](https://docs.spring.io/spring-boot/docs/2.7.0-SNAPSHOT/reference/html/web.html#web.graphql.schema) from a
well-known classpath location, but you can change that to a location on the file system
via `FileSystemResource`, to byte content via `ByteArrayResource`, or implement a custom`Resource` that loads schema files from a remote location or storage.

#### 4.1.2. Schema Creation

By default, `GraphQlSource.Builder` uses the GraphQL Java `GraphQLSchemaGenerator` to
create the `graphql.schema.GraphQLSchema`. This works for most applications, but if
necessary, you can hook into the schema creation through the builder:

```
// Typically, accessed through Spring Boot's GraphQlSourceBuilderCustomizer
GraphQlSource.Builder builder = ...

builder.schemaResources(..)
        .configureRuntimeWiring(..)
        .schemaFactory((typeDefinitionRegistry, runtimeWiring) -> {
            // create GraphQLSchema
        })

```

The primary reason for this is to create the schema through a federation library.

#### 4.1.3. `RuntimeWiringConfigurer`

You can use `RuntimeWiringConfigurer` to register:

* Custom scalar types.

* Directives handling code.

* `TypeResolver`, if you need to override the[Default `TypeResolver`](#execution-graphqlsource-default-type-resolver) for a type.

* `DataFetcher` for a field, although most applications will simply configure`AnnotatedControllerConfigurer`, which detects annotated, `DataFetcher` handler methods.
  The Spring Boot starter adds the `AnnotatedControllerConfigurer` by default.

The Spring Boot starter detects beans of type `RuntimeWiringConfigurer` and
registers them in the `GraphQlSource.Builder`. That means in most cases, you’ll' have
something like the following in your configuration:

```
@Configuration
public class GraphQlConfig {

    @Bean
    public RuntimeWiringConfigurer runtimeWiringConfigurer(BookRepository repository) {

        GraphQLScalarType scalarType = ... ;
        SchemaDirectiveWiring directiveWiring = ... ;
        DataFetcher dataFetcher = QuerydslDataFetcher.builder(repository).single();

        return wiringBuilder -> wiringBuilder
                .scalar(scalarType)
                .directiveWiring(directiveWiring)
                .type("Query", builder -> builder.dataFetcher("book", dataFetcher));
    }
}

```

If you need to add a `WiringFactory`, e.g. to make registrations that take into account
schema definitions, implement the alternative `configure` method that accepts both the`RuntimeWiring.Builder` and an output `List<WiringFactory>`. This allows you to add any
number of factories that are then invoked in sequence.

#### 4.1.4. Default `TypeResolver`

`GraphQlSource.Builder` registers `ClassNameTypeResolver` as the default `TypeResolver`to use for GraphQL Interfaces and Unions that don’t already have such a registration
through a [`RuntimeWiringConfigurer`](#execution-graphqlsource-runtimewiring-configurer). The purpose of
a `TypeResolver` in GraphQL Java is to determine the GraphQL Object type for values
returned from the `DataFetcher` for a GraphQL Interface or Union field.

`ClassNameTypeResolver` tries to match the simple class name of the value to a GraphQL
Object Type and if it is not successful, it also navigates its super types including
base classes and interfaces, looking for a match. `ClassNameTypeResolver` provides an
option to configure a name extracting function along with `Class` to GraphQL Object type
name mappings that should help to cover more corner cases.

#### 4.1.5. Operation Caching

GraphQL Java must *parse* and *validate* an operation before executing it. This may impact
performance significantly. To avoid the need to re-parse and validate, an application may
configure a `PreparsedDocumentProvider` that caches and reuses Document instances. The[GraphQL Java docs](https://www.graphql-java.com/documentation/execution/#query-caching) provide more details on
query caching through a `PreparsedDocumentProvider`.

In Spring GraphQL you can register a `PreparsedDocumentProvider` through`GraphQlSource.Builder#configureGraphQl`:
.

```
// Typically, accessed through Spring Boot's GraphQlSourceBuilderCustomizer
GraphQlSource.Builder builder = ...

// Create provider
PreparsedDocumentProvider provider = ...

builder.schemaResources(..)
        .configureRuntimeWiring(..)
        .configureGraphQl(graphQLBuilder -> graphQLBuilder.preparsedDocumentProvider(provider))

```

#### 4.1.6. Directives

The GraphQL language supports directives that "describe alternate runtime execution and
type validation behavior in a GraphQL document". Directives are similar to annotations in
Java but declared on types, fields, fragments and operations in a GraphQL document.

GraphQL Java provides the `SchemaDirectiveWiring` contract to help applications detect
and handle directives. For more details, see[Schema Directives](https://www.graphql-java.com/documentation/sdl-directives/) in the
GraphQL Java documentation.

In Spring GraphQL you can register a `SchemaDirectiveWiring` through a[`RuntimeWiringConfigurer`](#execution-graphqlsource-runtimewiring-configurer). The Spring Boot starter detects
such beans, so you might have something like:

```
@Configuration
public class GraphQlConfig {

    @Bean
    public RuntimeWiringConfigurer runtimeWiringConfigurer() {
        return builder -> builder.directiveWiring(new MySchemaDirectiveWiring());
    }

}

```

|   |For an example of directives support check out the[Extended Validation for Graphql Java](https://github.com/graphql-java/graphql-java-extended-validation)library.|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------|

### 4.2. Reactive `DataFetcher`

The default `GraphQlSource` builder enables support for a `DataFetcher` to return `Mono`or `Flux` which adapts those to a `CompletableFuture` where `Flux` values are aggregated
and turned into a List, unless the request is a GraphQL subscription request,
in which case the return value remains a Reactive Streams `Publisher` for streaming
GraphQL responses.

A reactive `DataFetcher` can rely on access to Reactor context propagated from the
transport layer, such as from a WebFlux request handling, see[WebFlux Context](#execution-context-webflux).

### 4.3. Context Propagation

Spring for GraphQL provides support to transparently propagate context from the [Web Transports](#web-transports),
through the GraphQL engine, and to `DataFetcher` and other components it invokes.
This includes both `ThreadLocal` context from the Spring MVC request handling thread and
Reactor `Context` from the WebFlux processing pipeline.

#### 4.3.1. WebMvc

A `DataFetcher` and other components invoked by GraphQL Java may not always execute on
the same thread as the Spring MVC handler, for example if an asynchronous[`WebInterceptor`](#web-interception) or `DataFetcher` switches to a different thread.

Spring for GraphQL supports propagating `ThreadLocal` values from the Servlet container
thread to the thread a `DataFetcher` and other components invoked by the GraphQL engine
execute on. To do this, an application needs to create a `ThreadLocalAccessor` to extract`ThreadLocal` values of interest:

```
public class RequestAttributesAccessor implements ThreadLocalAccessor {

    private static final String KEY = RequestAttributesAccessor.class.getName();

    @Override
    public void extractValues(Map<String, Object> container) {
        container.put(KEY, RequestContextHolder.getRequestAttributes());
    }

    @Override
    public void restoreValues(Map<String, Object> values) {
        if (values.containsKey(KEY)) {
            RequestContextHolder.setRequestAttributes((RequestAttributes) values.get(KEY));
        }
    }

    @Override
    public void resetValues(Map<String, Object> values) {
        RequestContextHolder.resetRequestAttributes();
    }

}

```

A `ThreadLocalAccessor` can be registered in the [WebGraphHandler](#web-interception)builder. The Boot starter detects beans of this type and automatically registers them for
Spring MVC application, see the[Web Endpoints](https://docs.spring.io/spring-boot/docs/2.7.0-SNAPSHOT/reference/html/web.html#web.graphql.web-endpoints) section.

#### 4.3.2. WebFlux

A [Reactive `DataFetcher`](#execution-reactive-datafetcher) can rely on access to Reactor context that
originates from the WebFlux request handling chain. This includes Reactor context
added by [WebInterceptor](#web-interception) components.

### 4.4. Exception Resolution

GraphQL Java applications can register a `DataFetcherExceptionHandler` to decide how to
represent exceptions from the data layer in the "errors" section of the GraphQL response.

Spring for GraphQL has a built-in `DataFetcherExceptionHandler` that is configured for use
by the [`GraphQLSource`](#execution-graphqlsource) builder. It enables applications to register one or
more Spring `DataFetcherExceptionResolver` components that are invoked sequentially
until one resolves the `Exception` to a list of `graphql.GraphQLError` objects.

`DataFetcherExceptionResolver` is an asynchronous contract. For most implementations, it
would be sufficient to extend `DataFetcherExceptionResolverAdapter` and override
one of its `resolveToSingleError` or `resolveToMultipleErrors` methods that
resolve exceptions synchronously.

A `GraphQLError` can be assigned an `graphql.ErrorClassification`. Spring for GraphQL
defines an `ErrorType` enum with common, error classification categories:

* `BAD_REQUEST`

* `UNAUTHORIZED`

* `FORBIDDEN`

* `NOT_FOUND`

* `INTERNAL_ERROR`

Applications can use this to classify errors. If an error remains unresolved, by
default it is marked as `INTERNAL_ERROR`.

### 4.5. Batch Loading

Given a `Book` and its `Author`, we can create one `DataFetcher` for a book and another
for its author. This allows selecting books with or without authors, but it means books
and authors aren’t loaded together, which is especially inefficient when querying multiple
books as the author for each book is loaded individually. This is known as the N+1 select
problem.

#### 4.5.1. `DataLoader`

GraphQL Java provides a `DataLoader` mechanism for batch loading of related entities.
You can find the full details in the[GraphQL Java docs](https://www.graphql-java.com/documentation/batching/). Below is a
summary of how it works:

1. Register `DataLoader`'s in the `DataLoaderRegistry` that can load entities, given unique keys.

2. `DataFetcher`'s can access `DataLoader`'s and use them to load entities by id.

3. A `DataLoader` defers loading by returning a future so it can be done in a batch.

4. `DataLoader`'s maintain a per request cache of loaded entities that can further
   improve efficiency.

#### 4.5.2. `BatchLoaderRegistry`

The complete batching loading mechanism in GraphQL Java requires implementing one of
several `BatchLoader` interface, then wrapping and registering those as `DataLoader`s
with a name in the `DataLoaderRegistry`.

The API in Spring GraphQL is slightly different. For registration, there is only one,
central `BatchLoaderRegistry` exposing factory methods and a builder to create and
register any number of batch loading functions:

```
@Configuration
public class MyConfig {

    public MyConfig(BatchLoaderRegistry registry) {

        registry.forTypePair(Long.class, Author.class).registerMappedBatchLoader((authorIds, env) -> {
            // return Mono<Map<Long, Author>
        });

        // more registrations ...
    }

}

```

The Spring Boot starter declares a `BatchLoaderRegistry` bean that you can inject into
your configuration, as shown above, or into any component such as a controller in order
register batch loading functions. In turn the `BatchLoaderRegistry` is injected into`ExecutionGraphQlService` where it ensures `DataLoader` registrations per request.

By default, the `DataLoader` name is based on the class name of the target entity.
This allows an `@SchemaMapping` method to declare a[DataLoader argument](#controllers-schema-mapping-data-loader) with a generic type, and
without the need for specifying a name. The name, however, can be customized through the`BatchLoaderRegistry` builder, if necessary, along with other `DataLoader` options.

For many cases, when loading related entities, you can use[@BatchMapping](#controllers-batch-mapping) controller methods, which are a shortcut
for and replace the need to use `BatchLoaderRegistry` and `DataLoader` directly.
s`BatchLoaderRegistry` provides other important benefits too. It supports access to
the same `GraphQLContext` from batch loading functions and from `@BatchMapping` methods,
as well as ensures [Context Propagation](#execution-context) to them. This is why applications are expected
to use it. It is possible to perform your own `DataLoader` registrations directly but
such registrations would forgo the above benefits.

#### 4.5.3. Testing Batch Loading

Start by having `BatchLoaderRegistry` perform registrations on a `DataLoaderRegistry`:

```
BatchLoaderRegistry batchLoaderRegistry = new DefaultBatchLoaderRegistry();
// perform registrations...

DataLoaderRegistry dataLoaderRegistry = DataLoaderRegistry.newRegistry().build();
batchLoaderRegistry.registerDataLoaders(dataLoaderRegistry, graphQLContext);

```

Now you can access and test individual `DataLoader`'s as follows:

```
DataLoader<Long, Book> loader = dataLoaderRegistry.getDataLoader(Book.class.getName());
loader.load(1L);
loader.loadMany(Arrays.asList(2L, 3L));
List<Book> books = loader.dispatchAndJoin(); // actual loading

assertThat(books).hasSize(3);
assertThat(books.get(0).getName()).isEqualTo("...");
// ...

```

## 5. Data Integration

Spring for GraphQL lets you leverage existing Spring technology, following common
programming models to expose underlying data sources through GraphQL.

This section discusses an integration layer for Spring Data that provides an easy way to
adapt a Querydsl or a Query by Example repository to a `DataFetcher`, including the
option for automated detection and GraphQL Query registration for repositories marked
with `@GraphQlRepository`.

### 5.1. Querydsl

Spring for GraphQL supports use of [Querydsl](http://www.querydsl.com/) to fetch data through
the Spring Data[Querydsl extension](https://docs.spring.io/spring-data/commons/docs/current/reference/html/#core.extensions).
Querydsl provides a flexible yet typesafe approach to express query predicates by
generating a meta-model using annotation processors.

For example, declare a repository as `QuerydslPredicateExecutor`:

```
public interface AccountRepository extends Repository<Account, Long>,
            QuerydslPredicateExecutor<Account> {
}

```

Then use it to create a `DataFetcher`:

```
// For single result queries
DataFetcher<Account> dataFetcher =
        QuerydslDataFetcher.builder(repository).single();

// For multi-result queries
DataFetcher<Iterable<Account>> dataFetcher =
        QuerydslDataFetcher.builder(repository).many();

```

You can now register the above `DataFetcher` through a[`RuntimeWiringConfigurer`](#execution-graphqlsource-runtimewiring-configurer).

The `DataFetcher` builds a Querydsl `Predicate` from GraphQL request parameters, and
uses it to fetch data. Spring Data supports `QuerydslPredicateExecutor` for JPA,
MongoDB, and LDAP.

If the repository is `ReactiveQuerydslPredicateExecutor`, the builder returns`DataFetcher<Mono<Account>>` or `DataFetcher<Flux<Account>>`. Spring Data supports this
variant for MongoDB.

#### 5.1.1. Build Setup

To configure Querydsl in your build, follow the[official reference documentation](https://querydsl.com/static/querydsl/latest/reference/html/ch02.html):

For example:

Gradle

```
dependencies {
    //...

    annotationProcessor "com.querydsl:querydsl-apt:$querydslVersion:jpa",
            'org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.2.Final',
            'javax.annotation:javax.annotation-api:1.3.2'
}

compileJava {
    options.annotationProcessorPath = configurations.annotationProcessor
}
```

Maven

```
<dependencies>
    <!-- ... -->
    <dependency>
        <groupId>com.querydsl</groupId>
        <artifactId>querydsl-apt</artifactId>
        <version>${querydsl.version}</version>
        <classifier>jpa</classifier>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.hibernate.javax.persistence</groupId>
        <artifactId>hibernate-jpa-2.1-api</artifactId>
        <version>1.0.2.Final</version>
    </dependency>
    <dependency>
        <groupId>javax.annotation</groupId>
        <artifactId>javax.annotation-api</artifactId>
        <version>1.3.2</version>
    </dependency>
</dependencies>
<plugins>
    <!-- Annotation processor configuration -->
    <plugin>
        <groupId>com.mysema.maven</groupId>
        <artifactId>apt-maven-plugin</artifactId>
        <version>${apt-maven-plugin.version}</version>
        <executions>
            <execution>
                <goals>
                    <goal>process</goal>
                </goals>
                <configuration>
                    <outputDirectory>target/generated-sources/java</outputDirectory>
                    <processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
                </configuration>
            </execution>
        </executions>
    </plugin>
</plugins>
```

The [webmvc-http](https://github.com/spring-projects/spring-graphql/tree/main/samples/webmvc-http) sample uses Querydsl for`artifactRepositories`.

#### 5.1.2. Customizations

`QuerydslDataFetcher` supports customizing how GraphQL arguments are bound onto properties
to create a Querydsl `Predicate`. By default, arguments are bound as "is equal to" for
each available property. To customize that, you can use `QuerydslDataFetcher` builder
methods to provide a `QuerydslBinderCustomizer`.

A repository may itself be an instance of `QuerydslBinderCustomizer`. This is auto-detected
and transparently applied during [Auto-Registration](#data-querydsl-registration). However, when manually
building a `QuerydslDataFetcher` you will need to use builder methods to apply it.

`QuerydslDataFetcher` supports interface and DTO projections to transform query results
before returning these for further GraphQL processing.

|   |To learn what projections are, please refer to the[Spring Data docs](https://docs.spring.io/spring-data/commons/docs/current/reference/html/#projections).<br/>To understand how to use projections in GraphQL, please see [Selection Set vs Projections](#data-projections).|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

To use Spring Data projections with Querydsl repositories, create either a projection interface
or a target DTO class and configure it through the `projectAs` method to obtain a`DataFetcher` producing the target type:

```
class Account {

    String name, identifier, description;

    Person owner;
}

interface AccountProjection {

    String getName();

    String getIdentifier();
}

// For single result queries
DataFetcher<AccountProjection> dataFetcher =
        QuerydslDataFetcher.builder(repository).projectAs(AccountProjection.class).single();

// For multi-result queries
DataFetcher<Iterable<AccountProjection>> dataFetcher =
        QuerydslDataFetcher.builder(repository).projectAs(AccountProjection.class).many();

```

#### 5.1.3. Auto-Registration

If a repository is annotated with `@GraphQlRepository`, it is automatically registered
for queries that do not already have a registered `DataFetcher` and whose return type
matches that of the repository domain type. This includes both single value and multi-value
queries.

By default, the name of the GraphQL type returned by the query must match the simple name
of the repository domain type. If needed, you can use the `typeName` attribute of`@GraphQlRepository` to specify the target GraphQL type name.

Auto-registration detects if a given repository implements `QuerydslBinderCustomizer` and
transparently applies that through `QuerydslDataFetcher` builder methods.

Auto-registration is performed through a built-in `RuntimeWiringConfigurer` that can be
obtained from `QuerydslDataFetcher`. The[Boot starter](https://docs.spring.io/spring-boot/docs/2.7.0-SNAPSHOT/reference/html/web.html#web.graphql.data-query) automatically
detects `@GraphQlRepository` beans and uses them to initialize the`RuntimeWiringConfigurer` with.

Auto-registration does not support [customizations](#data-querybyexample-customizations).
If you need that, you’ll need to use `QueryByExampleDataFetcher` to build and
register the `DataFetcher` manually through a[`RuntimeWiringConfigurer`](#execution-graphqlsource-runtimewiring-configurer).

### 5.2. Query by Example

Spring Data supports the use of[Query by Example](https://docs.spring.io/spring-data/commons/docs/current/reference/html/#query-by-example)to fetch data. Query by Example (QBE) is a simple querying technique that does not require
you to write queries through store-specific query languages.

Start by declaring a repository that is `QueryByExampleExecutor`:

```
public interface AccountRepository extends Repository<Account, Long>,
            QueryByExampleExecutor<Account> {
}

```

Use `QueryByExampleDataFetcher` to turn the repository into a `DataFecher`:

```
// For single result queries
DataFetcher<Account> dataFetcher =
        QueryByExampleDataFetcher.builder(repository).single();

// For multi-result queries
DataFetcher<Iterable<Account>> dataFetcher =
        QueryByExampleDataFetcher.builder(repository).many();

```

You can now register the above `DataFetcher` through a[`RuntimeWiringConfigurer`](#execution-graphqlsource-runtimewiring-configurer).

The `DataFetcher` uses the GraphQL arguments map to create the domain type of the
repository and use that as the example object to fetch data with. Spring Data supports`QueryByExampleDataFetcher` for JPA, MongoDB, Neo4j, and Redis.

If the repository is `ReactiveQueryByExampleExecutor`, the builder returns`DataFetcher<Mono<Account>>` or `DataFetcher<Flux<Account>>`. Spring Data supports this
variant for MongoDB, Neo4j, Redis, and R2dbc.

#### 5.2.1. Build Setup

Query by Example is already included in the Spring Data modules for the data stores where
it is supported, so no extra setup is required to enable it.

#### 5.2.2. Customizations

`QueryByExampleDataFetcher` supports interface and DTO projections to transform query
results before returning these for further GraphQL processing.

|   |To learn what projections are, please refer to the[Spring Data documentation](https://docs.spring.io/spring-data/commons/docs/current/reference/html/#projections).<br/>To understand the role of projections in GraphQL, please see [Selection Set vs Projections](#data-projections).|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

To use Spring Data projections with Query by Example repositories, create either a projection interface
or a target DTO class and configure it through the `projectAs` method to obtain a`DataFetcher` producing the target type:

```
class Account {

    String name, identifier, description;

    Person owner;
}

interface AccountProjection {

    String getName();

    String getIdentifier();
}

// For single result queries
DataFetcher<AccountProjection> dataFetcher =
        QueryByExampleDataFetcher.builder(repository).projectAs(AccountProjection.class).single();

// For multi-result queries
DataFetcher<Iterable<AccountProjection>> dataFetcher =
        QueryByExampleDataFetcher.builder(repository).projectAs(AccountProjection.class).many();

```

#### 5.2.3. Auto-Registration

If a repository is annotated with `@GraphQlRepository`, it is automatically registered
for queries that do not already have a registered `DataFetcher` and whose return type
matches that of the repository domain type. This includes both single value and multi-value
queries.

By default, the name of the GraphQL type returned by the query must match the simple name
of the repository domain type. If needed, you can use the `typeName` attribute of`@GraphQlRepository` to specify the target GraphQL type name.

Auto-registration is performed through a built-in `RuntimeWiringConfigurer` that can be
obtained from `QueryByExampleDataFetcher`. The[Boot starter](https://docs.spring.io/spring-boot/docs/2.7.0-SNAPSHOT/reference/html/web.html#web.graphql.data-query) automatically
detects `@GraphQlRepository` beans and uses them to initialize the`RuntimeWiringConfigurer` with.

Auto-registration does not support [customizations](#data-querybyexample-customizations).
If you need that, you’ll need to use `QueryByExampleDataFetcher` to build and
register the `DataFetcher` manually through a[`RuntimeWiringConfigurer`](#execution-graphqlsource-runtimewiring-configurer).

### 5.3. Selection Set vs Projections

A common question that arises is, how GraphQL selection sets compare to[Spring Data projections](https://docs.spring.io/spring-data/commons/docs/current/reference/html/#projections)and what role does each play?

The short answer is that Spring for GraphQL is not a data gateway that translates GraphQL
queries directly into SQL or JSON queries. Instead, it lets you leverage existing Spring
technology and does not assume a one for one mapping between the GraphQL schema and the
underlying data model. That is why client-driven selection and server-side transformation
of the data model can play complementary roles.

To better understand, consider that Spring Data promotes domain-driven (DDD) design as
the recommended approach to manage complexity in the data layer. In DDD, it is important
to adhere to the constraints of an aggregate. By definition an aggregate is valid only if
loaded in its entirety, since a partially loaded aggregate may impose limitations on
aggregate functionality.

In Spring Data you can choose whether you want your aggregate be exposed as is, or
whether to apply transformations to the data model before returning it as a GraphQL
result. Sometimes it’s enough to do the former, and by default the[Querydsl](#data-querydsl) and the [Query by Example](#data-querybyexample) integrations turn the GraphQL
selection set into property path hints that the underlying Spring Data module uses to
limit the selection.

In other cases, it’s useful to reduce or even transform the underlying data model in
order to adapt to the GraphQL schema. Spring Data supports this through Interface
and DTO Projections.

Interface projections define a fixed set of properties to expose where properties may or
may not be `null`, depending on the data store query result. There are two kinds of
interface projections both of which determine what properties to load from the underlying
data source:

* [Closed interface projections](https://docs.spring.io/spring-data/commons/docs/current/reference/html/#projections.interfaces.closed)are helpful if you cannot partially materialize the aggregate object, but you still
  want to expose a subset of properties.

* [Open interface projections](https://docs.spring.io/spring-data/commons/docs/current/reference/html/#projections.interfaces.open)leverage Spring’s `@Value` annotation and[SpEL](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#expressions) expressions to apply lightweight
  data transformations, such as concatenations, computations, or applying static functions
  to a property.

DTO projections offer a higher level of customization as you can place transformation
code either in the constructor or in getter methods.

DTO projections materialize from a query where the individual properties are
determined by the projection itself. DTO projections are commonly used with full-args
constructors (e.g. Java records), and therefore they can only be constructed if all
required fields (or columns) are part of the database query result.

## 6. Annotated Controllers

Spring for GraphQL provides an annotation-based programming model where `@Controller`components use annotations to declare handler methods with flexible method signatures to
fetch the data for specific GraphQL fields. For example:

```
@Controller
public class GreetingController {

        @QueryMapping (1)
        public String hello() { (2)
            return "Hello, world!";
        }

}

```

|**1**|      Bind this method to a query, i.e. a field under the Query type.      |
|-----|---------------------------------------------------------------------------|
|**2**|Determine the query from the method name if not declared on the annotation.|

Spring for GraphQL uses `RuntimeWiring.Builder` to register the above handler method as a`graphql.schema.DataFetcher` for the query named "hello".

### 6.1. Declaration

You can define `@Controller` beans as standard Spring bean definitions. The`@Controller` stereotype allows for auto-detection, aligned with Spring general
support for detecting `@Controller` and `@Component` classes on the classpath and
auto-registering bean definitions for them. It also acts as a stereotype for the annotated
class, indicating its role as a data fetching component in a GraphQL application.

`AnnotatedControllerConfigurer` detects `@Controller` beans and registers their
annotated handler methods as `DataFetcher`s via `RuntimeWiring.Builder`. It is an
implementation of `RuntimeWiringConfigurer` which can be added to `GraphQlSource.Builder`.
The Spring Boot starter automatically declares `AnnotatedControllerConfigurer` as a bean
and adds all `RuntimeWiringConfigurer` beans to `GraphQlSource.Builder` and that enables
support for annotated `DataFetcher`s, see the[GraphQL RuntimeWiring](https://docs.spring.io/spring-boot/docs/2.7.0-SNAPSHOT/reference/html/web.html#web.graphql.runtimewiring) section
in the Boot starter documentation.

### 6.2. `@SchemaMapping`

The `@SchemaMapping` annotation maps a handler method to a field in the GraphQL schema
and declares it to be the `DataFetcher` for that field. The annotation can specify the
parent type name, and the field name:

```
@Controller
public class BookController {

    @SchemaMapping(typeName="Book", field="author")
    public Author getAuthor(Book book) {
        // ...
    }
}

```

The `@SchemaMapping` annotation can also leave out those attributes, in which case the
field name defaults to the method name, while the type name defaults to the simple class
name of the source/parent object injected into the method. For example, the below
defaults to type "Book" and field "author":

```
@Controller
public class BookController {

    @SchemaMapping
    public Author author(Book book) {
        // ...
    }
}

```

The `@SchemaMapping` annotation can be declared at the class level to specify a default
type name for all handler methods in the class.

```
@Controller
@SchemaMapping(typeName="Book")
public class BookController {

    // @SchemaMapping methods for fields of the "Book" type

}

```

`@QueryMapping`, `@MutationMapping`, and `@SubscriptionMapping` are meta annotations that
are themselves annotated with `@SchemaMapping` and have the typeName preset to `Query`,`Mutation`, or `Subscription` respectively. Effectively, these are shortcut annotations
for fields under the Query, Mutation, and Subscription types respectively. For example:

```
@Controller
public class BookController {

    @QueryMapping
    public Book bookById(@Argument Long id) {
        // ...
    }

    @MutationMapping
    public Book addBook(@Argument BookInput bookInput) {
        // ...
    }

    @SubscriptionMapping
    public Flux<Book> newPublications() {
        // ...
    }
}

```

`@SchemaMapping` handler methods have flexible signatures and can choose from a range of
method arguments and return values..

#### 6.2.1. Method Signature

Schema mapping handler methods can have any of the following method arguments:

|        Method Argument        |                                                                      Description                                                                       |
|-------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------|
|          `@Argument`          |      For access to a named field argument converted to a higher-level, typed Object.<br/>See [`@Argument`](#controllers-schema-mapping-argument).      |
|         `@Arguments`          |      For access to all field arguments converted to a higher-level, typed Object.<br/>See [`@Arguments`](#controllers-schema-mapping-arguments).       |
| `@ProjectedPayload` Interface |For access to field arguments through a project interface.<br/>See [`@ProjectPayload` Interface](#controllers-schema-mapping-projectedpayload-argument).|
|            Source             |             For access to the source (i.e. parent/container) instance of the field.<br/>See [Source](#controllers-schema-mapping-source).              |
|         `DataLoader`          |               For access to a `DataLoader` in the `DataLoaderRegistry`.<br/>See [`DataLoader`](#controllers-schema-mapping-data-loader).               |
|        `@ContextValue`        | For access to a value from the localContext, if it is an instance of `GraphQLContext`,<br/>or from the `GraphQLContext` of `DataFetchingEnvironment`.  |
|       `GraphQLContext`        |                                             For access to the context from the `DataFetchingEnvironment`.                                              |
|   `java.security.Principal`   |                                                Obtained from the Spring Security context, if available.                                                |
|  `@AuthenticationPrincipal`   |                                    For access to `Authentication#getPrincipal()` from the Spring Security context.                                     |
|`DataFetchingFieldSelectionSet`|                                  For access to the selection set for the query through the `DataFetchingEnvironment`.                                  |
| `Locale`, `Optional<Locale>`  |                                             For access to the `Locale` from the `DataFetchingEnvironment`.                                             |
|   `DataFetchingEnvironment`   |                                             For direct access to the underlying `DataFetchingEnvironment`.                                             |

Schema mapping handler methods can return any value, including Reactor `Mono` and`Flux` as described in [Reactive `DataFetcher`](#execution-reactive-datafetcher).

#### 6.2.2. `@Argument`

In GraphQL Java, `DataFetchingEnvironment` provides access to a map of field-specific
argument values. The values can be simple scalar values (e.g. String, Long), a `Map` of
values for more complex input, or a `List` of values.

Use the `@Argument` annotation to inject a named field argument into a handler method.
The method parameter can be a higher-level, typed Object of any type. It is created and
initialized from the named field argument value(s), either matching them to single data
constructor parameters, or using the default constructor and then matching keys onto
Object properties through a `org.springframework.validation.DataBinder`:

```
@Controller
public class BookController {

    @QueryMapping
    public Book bookById(@Argument Long id) {
        // ...
    }

    @MutationMapping
    public Book addBook(@Argument BookInput bookInput) {
        // ...
    }
}

```

By default, if the method parameter name is available (requires the `-parameters` compiler
flag with Java 8+ or debugging info from the compiler), it is used to look up the argument.
If needed, you can customize the name through the annotation, e.g. `@Argument("bookInput")`.

|   |The `@Argument` annotation does not have a "required" flag, nor the option to<br/>specify a default value. Both of these can be specified at the GraphQL schema level and<br/>are enforced by the GraphQL Engine.|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

You can use `@Argument` on a `Map<String, Object>` argument, to obtain all argument
values. The name attribute on `@Argument` must not be set.

#### 6.2.3. `@Arguments`

Use the `@Arguments` annotation, if you want to bind the full arguments map onto a single
target Object, in contrast to `@Argument`, which binds a specific, named argument.

For example, `@Argument BookInput bookInput` uses the value of the argument "bookInput"
to initialize `BookInput`, while `@Arguments` uses the full arguments map and in that
case, top-level arguments are bound to `BookInput` properties.

#### 6.2.4. `@Argument(s)` Validation

If a [Bean Validation](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#validation-beanvalidation-overview)`Validator` (or typically, a `LocalValidatorFactoryBean`) bean is present in the application context,
the `AnnotatedControllerConfigurer` will auto-detect it and configure support for validation.
Controller arguments annotated with `@Valid` and `@Validated` are then validated before method invocation.

Bean Validation lets you declare constraints on types, as the following example shows:

```
public class BookInput {

    @NotNull
    private String title;

    @NotNull
    @Size(max=13)
    private String isbn;
}

```

We can then mark our argument for validation with `@Valid`:

```
@Controller
public class BookController {

    @MutationMapping
    public Book addBook(@Argument @Valid BookInput bookInput) {
        // ...
    }
}

```

If an error occurs during validation, a `ConstraintViolationException` is thrown and can be
later [resolved with a custom `DataFetcherExceptionResolver`](#execution-exceptions).

|   |Unlike Spring MVC, handler method signatures do not support the injection of `BindingResult`for reacting to validation errors: those are globally dealt with as exceptions.|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

#### 6.2.5. `@ProjectPayload` Interface

As an alternative to using complete Objects with [`@Argument`](#controllers-schema-mapping-argument),
you can also use a projection interface to access GraphQL request arguments through a
well-defined, minimal interface. Argument projections are provided by[Spring Data’s Interface projections](https://docs.spring.io/spring-data/commons/docs/current/reference/html/#projections.interfaces)when Spring Data is on the class path.

To make use of this, create an interface annotated with `@ProjectedPayload` and declare
it as a controller method parameter. If the parameter is annotated with `@Argument`,
it applies to an individual argument within the `DataFetchingEnvironment.getArguments()`map. When declared without `@Argument`, the projection works on top-level arguments in
the complete arguments map.

For example:

```
@Controller
public class BookController {

    @QueryMapping
    public Book bookById(BookIdProjection bookId) {
        // ...
    }

    @MutationMapping
    public Book addBook(@Argument BookInputProjection bookInput) {
        // ...
    }
}

@ProjectedPayload
interface BookIdProjection {

    Long getId();
}

@ProjectedPayload
interface BookInputProjection {

    String getName();

    @Value("#{target.author + ' ' + target.name}")
    String getAuthorAndName();
}

```

#### 6.2.6. Source

In GraphQL Java, the `DataFetchingEnvironment` provides access to the source (i.e.
parent/container) instance of the field. To access this, simply declare a method parameter
of the expected target type.

```
@Controller
public class BookController {

    @SchemaMapping
    public Author author(Book book) {
        // ...
    }
}

```

The source method argument also helps to determine the type name for the mapping.
If the simple name of the Java class matches the GraphQL type, then there is no need to
explicitly specify the type name in the `@SchemaMapping` annotation.

|   |A [`@BatchMapping`](#controllers-batch-mapping) handler method can batch load all authors for a query,<br/>given a list of source/parent books objects.|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------|

#### 6.2.7. `DataLoader`

When you register a batch loading function for an entity, as explained in[Batch Loading](#execution-batching), you can access the `DataLoader` for the entity by declaring a
method argument of type `DataLoader` and use it to load the entity:

```
@Controller
public class BookController {

    public BookController(BatchLoaderRegistry registry) {
        registry.forTypePair(Long.class, Author.class).registerMappedBatchLoader((authorIds, env) -> {
            // return Map<Long, Author>
        });
    }

    @SchemaMapping
    public CompletableFuture<Author> author(Book book, DataLoader<Long, Author> loader) {
        return loader.load(book.getAuthorId());
    }

}

```

By default, `BatchLoaderRegistry` uses the full class name of the value type (e.g. the
class name for `Author`) for the key of the registration, and therefore simply declaring
the `DataLoader` method argument with generic types provides enough information
to locate it in the `DataLoaderRegistry`. As a fallback, the `DataLoader` method argument
resolver will also try the method argument name as the key but typically that should not
be necessary.

Note that for many cases with loading related entities, where the `@SchemaMapping` simply
delegates to a `DataLoader`, you can reduce boilerplate by using a[@BatchMapping](#controllers-batch-mapping) method as described in the next section.

### 6.3. `@BatchMapping`

[Batch Loading](#execution-batching) addresses the N+1 select problem through the use of an`org.dataloader.DataLoader` to defer the loading of individual entity instances, so they
can be loaded together. For example:

```
@Controller
public class BookController {

    public BookController(BatchLoaderRegistry registry) {
        registry.forTypePair(Long.class, Author.class).registerMappedBatchLoader((authorIds, env) -> {
            // return Map<Long, Author>
        });
    }

    @SchemaMapping
    public CompletableFuture<Author> author(Book book, DataLoader<Long, Author> loader) {
        return loader.load(book.getAuthorId());
    }

}

```

For the straight-forward case of loading an associated entity, shown above, the`@SchemaMapping` method does nothing more than delegate to the `DataLoader`. This is
boilerplate that can be avoided with a `@BatchMapping` method. For example:

```
@Controller
public class BookController {

    @BatchMapping
    public Mono<Map<Book, Author>> author(List<Book> books) {
        // ...
    }
}

```

The above becomes a batch loading function in the `BatchLoaderRegistry`where keys are `Book` instances and the loaded values their authors. In addition, a`DataFetcher` is also transparently bound to the `author` field of the type `Book`, which
simply delegates to the `DataLoader` for authors, given its source/parent `Book` instance.

|   |To be used as a unique key, `Book` must implement `hashcode` and `equals`.|
|---|--------------------------------------------------------------------------|

By default, the field name defaults to the method name, while the type name defaults to
the simple class name of the input `List` element type. Both can be customized through
annotation attributes. The type name can also be inherited from a class level`@SchemaMapping`.

#### 6.3.1. Method Signature

Batch mapping methods support the following arguments:

|     Method Argument     |                                                                       Description                                                                       |
|-------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------|
|        `List<K>`        |                                                               The source/parent objects.                                                                |
|`java.security.Principal`|                                                  Obtained from Spring Security context, if available.                                                   |
|     `@ContextValue`     |For access to a value from the `GraphQLContext` of `BatchLoaderEnvironment`,<br/>which is the same context as the one from the `DataFetchingEnvironment`.|
|    `GraphQLContext`     |        For access to the context from the `BatchLoaderEnvironment`,<br/>which is the same context as the one from the `DataFetchingEnvironment`.        |
|`BatchLoaderEnvironment` |                             The environment that is available in GraphQL Java to a`org.dataloader.BatchLoaderWithContext`.                              |

Batch mapping methods can return:

|     Return Type     |                                                       Description                                                        |
|---------------------|--------------------------------------------------------------------------------------------------------------------------|
|  `Mono<Map<K,V>>`   |                          A map with parent objects as keys, and batch loaded objects as values.                          |
|      `Flux<V>`      |A sequence of batch loaded objects that must be in the same order as the source/parent<br/>objects passed into the method.|
|`Map<K,V>`, `List<V>`|                                 Imperative variants, e.g. without remote calls to make.                                  |

## 7. Security

The path to a [Web](#web-transports) GraphQL endpoint can be secured with HTTP
URL security to ensure that only authenticated users can access it. This does not,
however, differentiate among different GraphQL requests on such a shared endpoint on
a single URL.

To apply more fine-grained security, add Spring Security annotations such as`@PreAuthorize` or `@Secured` to service methods involved in fetching specific parts of
the GraphQL response. This should work due to [Context Propagation](#execution-context) that aims to make
Security, and other context, available at the data fetching level.

The Spring for GraphQL repository contains samples for[Spring MVC](https://github.com/spring-projects/spring-graphql/tree/main/samples/webmvc-http-security) and for[WebFlux](https://github.com/spring-projects/spring-graphql/tree/main/samples/webflux-security).

## 8. Testing

It’s possible to test GraphQL requests with Spring’s `WebTestClient`, just sending and
receiving JSON, but a number of GraphQL specific details make this approach more
cumbersome than is necessary.

To get the full testing support, you’ll need to add the `spring-graphql-test` dependdency
in your build:

Gradle

```
dependencies {
    // ...
    testImplementation 'org.springframework.graphql:spring-graphql-test:1.0.0-SNAPSHOT'
}
```

Maven

```
<dependencies>
    <!-- ... -->
    <dependency>
        <groupId>org.springframework.graphql</groupId>
        <artifactId>spring-graphql-test</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <scope>test</scope>
    </dependency>
</dependencies>
```

### 8.1. `GraphQlTester`

`GraphQlTester` defines a workflow to test GraphQL requests with the following benefits:

* Verify no unexpected errors under the "errors" key in the response.

* Decode under the "data" key in the response.

* Use JsonPath to decode different parts of the response.

* Test subscriptions.

To create `GraphQlTester`, you only need a `GraphQlService`, and no transport:

```
GraphQlSource graphQlSource = GraphQlSource.builder()
        .schemaResources(...)
        .runtimeWiringConfigurer(...)
        .build();

GraphQlService graphQlService = new ExecutionGraphQlService(graphQlSource);

GraphQlTester graphQlTester = GraphQlTester.builder(graphQlService).build();

```

### 8.2. `WebGraphQlTester`

`WebGraphQlTester` extends `GraphQlTester` to add a workflow and configuration specific
to [Web Transports](#web-transports), and it always verifies GraphQL HTTP responses are 200 (OK).

To create `WebGraphQlTester`, you need one of the following inputs:

* `WebTestClient` — perform requests as an HTTP client, either against [HTTP](#web-http)handlers without a server, or against a live server.

* `WebGraphQlHandler` — perform requests through the [Web Interception](#web-interception) chain used
  by both [HTTP](#web-http) and [WebSocket](#web-websocket) handlers, which in effect is testing without
  a Web framework. One reason to use this is for [Subscriptions](#testing-subscriptions).

For Spring WebFlux without a server, you can point to your Spring configuration:

```
ApplicationContext context = ... ;

WebTestClient client =
        WebTestClient.bindToApplicationContext(context)
                .configureClient()
                .baseUrl("/graphql")
                .build();

WebGraphQlTester tester = WebGraphQlTester.builder(client).build();

```

For Spring MVC without a server, the same but using `MockMvcWebTestClient`:

```
WebApplicationContext context = ... ;

WebTestClient client =
        MockMvcWebTestClient.bindToApplicationContext(context)
                .configureClient()
                .baseUrl("/graphql")
                .build();

WebGraphQlTester tester = WebGraphQlTester.builder(client).build();

```

To test against a live, running server:

```
WebTestClient client =
        WebTestClient.bindToServer()
                .baseUrl("http://localhost:8080/graphql")
                .build();

WebGraphQlTester tester = WebGraphQlTester.builder(client).build();

```

`WebGraphQlTester` supports setting HTTP request headers and access to HTTP response
headers. This may be useful to inspect or set security related headers.

```
this.graphQlTester.queryName("{ myQuery }")
        .httpHeaders(headers -> headers.setBasicAuth("rob", "..."))
        .execute()
        .httpHeadersSatisfy(headers -> {
            // check response headers
        })
        .path("myQuery.field1").entity(String.class).isEqualTo("value1")
        .path("myQuery.field2").entity(String.class).isEqualTo("value2");

```

You can also set default request headers at the builder level:

```
WebGraphQlTester tester = WebGraphQlTester.builder(client)
    .defaultHttpHeaders(headers -> headers.setBasicAuth("rob", "..."))
    .build();

```

### 8.3. Queries

Below is an example query test using[JsonPath](https://github.com/json-path/JsonPath) to extract all release versions in the
GraphQL response.

```
String query = "{" +
        "  project(slug:\"spring-framework\") {" +
        "   releases {" +
        "     version" +
        "   }"+
        "  }" +
        "}";

graphQlTester.query(query)
        .execute()
        .path("project.releases[*].version")
        .entityList(String.class)
        .hasSizeGreaterThan(1);

```

The JsonPath is relative to the "data" section of the response.

You can also create query files with extensions `.graphql` or `.gql` under `"graphql/"` on
the classpath and refer to them by file name. For example, given a file called`projectReleases.graphql` in `src/main/resources/graphql`, with content:

```
query projectReleases($slug: ID!) {
    project(slug: $slug) {
        releases {
            version
        }
    }
}
```

You can write the same test as follows:

```
graphQlTester.queryName("projectReleases") (1)
        .variable("slug", "spring-framework") (2)
        .execute()
        .path("project.releases[*].version")
        .entityList(String.class)
        .hasSizeGreaterThan(1);

```

|**1**|Refer to the query in the file named "projectReleases".|
|-----|-------------------------------------------------------|
|**2**|               Set the `slug` variable.                |

|   |The "JS GraphQL" plugin for IntelliJ supports GraphQL query files with code completion.|
|---|---------------------------------------------------------------------------------------|

### 8.4. Errors

Verify won’t succeed when there are errors under the "errors" key in the response.

If necessary to ignore an error, use an error filter `Predicate`:

```
graphQlTester.query(query)
        .execute()
        .errors()
        .filter(error -> ...)
        .verify()
        .path("project.releases[*].version")
        .entityList(String.class)
        .hasSizeGreaterThan(1);

```

An error filter can be registered globally and apply to all tests:

```
WebGraphQlTester graphQlTester = WebGraphQlTester.builder(client)
        .errorFilter(error -> ...)
        .build();

```

Or to expect an error, and in contrast to `filter`, throw an assertion error
when it doesn’t exist in the response:

```
graphQlTester.query(query)
        .execute()
        .errors()
        .expect(error -> ...)
        .verify()
        .path("project.releases[*].version")
        .entityList(String.class)
        .hasSizeGreaterThan(1);

```

Or inspect all errors directly and that also marks them as filtered:

```
graphQlTester.query(query)
        .execute()
        .errors()
        .satisfy(errors -> {
            // ...
        });

```

If a request does not have any response data (e.g. mutation), use `executeAndVerify`instead of `execute` to verify there are no errors in the response:

```
graphQlTester.query(query).executeAndVerify();

```

### 8.5. Subscriptions

The `executeSubscription` method defines a workflow specific to subscriptions which return
a stream of responses instead of a single response.

To test subscriptions, you can create `GraphQlTester` with a `GraphQlService`, which
calls `graphql.GraphQL` directly and that returns a stream of responses:

```
GraphQlService service = ... ;

GraphQlTester graphQlTester = GraphQlTester.builder(service).build();

Flux<String> result = graphQlTester.query("subscription { greetings }")
    .executeSubscription()
    .toFlux("greetings", String.class);  // decode each response

```

The `StepVerifier` from Project Reactor is useful to verify a stream:

```
Flux<String> result = graphQlTester.query("subscription { greetings }")
    .executeSubscription()
    .toFlux("greetings", String.class);

StepVerifier.create(result)
        .expectNext("Hi")
        .expectNext("Bonjour")
        .expectNext("Hola")
        .verifyComplete();

```

To test with the [Web Interception](#web-interception) chain, you can create `WebGraphQlTester` with a`WebGraphQlHandler`:

```
GraphQlService service = ... ;

WebGraphQlHandler handler = WebGraphQlHandler.builder(service)
    .interceptor((input, next) -> next.handle(input))
    .build();

WebGraphQlTester graphQlTester = WebGraphQlTester.builder(handler).build();

```

Currently, Spring for GraphQL does not support testing with a WebSocket client, and it
cannot be used for integration test of GraphQL over WebSocket requests.

## 9. Samples

This Spring for GraphQL repository contains [sample applications](https://github.com/spring-projects/spring-graphql/tree/main/samples) for
various scenarios.

You can run those by cloning this repository and running main application classes from
your IDE or by typing the following on the command line:

```
$ ./gradlew :samples:{sample-directory-name}:bootRun
```