Skip to content

Commit 74ba906

Browse files
committed
Polishing CORS support
1 parent b830fe9 commit 74ba906

File tree

4 files changed

+65
-59
lines changed

4 files changed

+65
-59
lines changed

graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/GraphQlCorsProperties.java

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.springframework.boot.context.properties.ConfigurationProperties;
2525
import org.springframework.boot.context.properties.PropertyMapper;
2626
import org.springframework.boot.convert.DurationUnit;
27+
import org.springframework.lang.Nullable;
2728
import org.springframework.util.CollectionUtils;
2829
import org.springframework.web.cors.CorsConfiguration;
2930

@@ -37,29 +38,31 @@
3738
@ConfigurationProperties(prefix = "spring.graphql.cors")
3839
public class GraphQlCorsProperties {
3940
/**
40-
* Comma-separated list of origins to allow. '*' allows all origins. When credentials
41-
* are allowed, '*' cannot be used and origin patterns should be configured instead.
42-
* When no allowed origins or allowed origin patterns are set, CORS support is
43-
* disabled.
41+
* Comma-separated list of origins to allow with '*' allowing all origins.
42+
* When allow-credentials is enabled, '*' cannot be used, and setting
43+
* origin patterns should be considered instead.
44+
* When neither allowed origins nor allowed origin patterns are set,
45+
* cross-origin requests are effectively disabled.
4446
*/
4547
private List<String> allowedOrigins = new ArrayList<>();
4648

4749
/**
48-
* Comma-separated list of origin patterns to allow. Unlike allowed origins which only
49-
* supports '*', origin patterns are more flexible (for example
50-
* 'https://*.example.com') and can be used when credentials are allowed. When no
51-
* allowed origin patterns or allowed origins are set, CORS support is disabled.
50+
* Comma-separated list of origin patterns to allow. Unlike allowed origins
51+
* which only support '*', origin patterns are more flexible, e.g.
52+
* 'https://*.example.com', and can be used with allow-credentials.
53+
* When neither allowed origins nor allowed origin patterns are set,
54+
* cross-origin requests are effectively disabled.
5255
*/
5356
private List<String> allowedOriginPatterns = new ArrayList<>();
5457

5558
/**
56-
* Comma-separated list of methods to allow. '*' allows all methods. When not set,
57-
* defaults to GET.
59+
* Comma-separated list of HTTP methods to allow. '*' allows all methods.
60+
* When not set, defaults to GET.
5861
*/
5962
private List<String> allowedMethods = new ArrayList<>();
6063

6164
/**
62-
* Comma-separated list of headers to allow in a request. '*' allows all headers.
65+
* Comma-separated list of HTTP headers to allow in a request. '*' allows all headers.
6366
*/
6467
private List<String> allowedHeaders = new ArrayList<>();
6568

@@ -71,6 +74,7 @@ public class GraphQlCorsProperties {
7174
/**
7275
* Whether credentials are supported. When not set, credentials are not supported.
7376
*/
77+
@Nullable
7478
private Boolean allowCredentials;
7579

7680
/**
@@ -120,6 +124,7 @@ public void setExposedHeaders(List<String> exposedHeaders) {
120124
this.exposedHeaders = exposedHeaders;
121125
}
122126

127+
@Nullable
123128
public Boolean getAllowCredentials() {
124129
return this.allowCredentials;
125130
}
@@ -136,19 +141,20 @@ public void setMaxAge(Duration maxAge) {
136141
this.maxAge = maxAge;
137142
}
138143

144+
@Nullable
139145
public CorsConfiguration toCorsConfiguration() {
140146
if (CollectionUtils.isEmpty(this.allowedOrigins) && CollectionUtils.isEmpty(this.allowedOriginPatterns)) {
141147
return null;
142148
}
143149
PropertyMapper map = PropertyMapper.get();
144-
CorsConfiguration configuration = new CorsConfiguration();
145-
map.from(this::getAllowedOrigins).to(configuration::setAllowedOrigins);
146-
map.from(this::getAllowedOriginPatterns).to(configuration::setAllowedOriginPatterns);
147-
map.from(this::getAllowedHeaders).whenNot(CollectionUtils::isEmpty).to(configuration::setAllowedHeaders);
148-
map.from(this::getAllowedMethods).whenNot(CollectionUtils::isEmpty).to(configuration::setAllowedMethods);
149-
map.from(this::getExposedHeaders).whenNot(CollectionUtils::isEmpty).to(configuration::setExposedHeaders);
150-
map.from(this::getMaxAge).whenNonNull().as(Duration::getSeconds).to(configuration::setMaxAge);
151-
map.from(this::getAllowCredentials).whenNonNull().to(configuration::setAllowCredentials);
152-
return configuration;
150+
CorsConfiguration config = new CorsConfiguration();
151+
map.from(this::getAllowedOrigins).to(config::setAllowedOrigins);
152+
map.from(this::getAllowedOriginPatterns).to(config::setAllowedOriginPatterns);
153+
map.from(this::getAllowedHeaders).whenNot(CollectionUtils::isEmpty).to(config::setAllowedHeaders);
154+
map.from(this::getAllowedMethods).whenNot(CollectionUtils::isEmpty).to(config::setAllowedMethods);
155+
map.from(this::getExposedHeaders).whenNot(CollectionUtils::isEmpty).to(config::setExposedHeaders);
156+
map.from(this::getMaxAge).whenNonNull().as(Duration::getSeconds).to(config::setMaxAge);
157+
map.from(this::getAllowCredentials).whenNonNull().to(config::setAllowCredentials);
158+
return config;
153159
}
154160
}

graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/GraphQlWebFluxAutoConfiguration.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -155,20 +155,20 @@ public HandlerMapping graphQlWebSocketEndpoint(GraphQlWebSocketHandler graphQlWe
155155
@Configuration(proxyBeanMethods = false)
156156
public static class GraphQlEndpointCorsConfiguration implements WebFluxConfigurer {
157157

158-
final GraphQlProperties graphql;
158+
final GraphQlProperties graphQlProperties;
159159

160-
final GraphQlCorsProperties cors;
160+
final GraphQlCorsProperties corsProperties;
161161

162-
public GraphQlEndpointCorsConfiguration(GraphQlProperties graphql, GraphQlCorsProperties cors) {
163-
this.graphql = graphql;
164-
this.cors = cors;
162+
public GraphQlEndpointCorsConfiguration(GraphQlProperties graphQlProps, GraphQlCorsProperties corsProps) {
163+
this.graphQlProperties = graphQlProps;
164+
this.corsProperties = corsProps;
165165
}
166166

167167
@Override
168168
public void addCorsMappings(CorsRegistry registry) {
169-
CorsConfiguration configuration = cors.toCorsConfiguration();
169+
CorsConfiguration configuration = this.corsProperties.toCorsConfiguration();
170170
if (configuration != null) {
171-
registry.addMapping(graphql.getPath()).combine(configuration);
171+
registry.addMapping(this.graphQlProperties.getPath()).combine(configuration);
172172
}
173173
}
174174
}

graphql-spring-boot-starter/src/main/java/org/springframework/graphql/boot/GraphQlWebMvcAutoConfiguration.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -176,20 +176,20 @@ public HandlerMapping graphQlWebSocketMapping(GraphQlWebSocketHandler handler, G
176176
@Configuration(proxyBeanMethods = false)
177177
public static class GraphQlEndpointCorsConfiguration implements WebMvcConfigurer {
178178

179-
final GraphQlProperties graphql;
179+
final GraphQlProperties graphQlProperties;
180180

181-
final GraphQlCorsProperties cors;
181+
final GraphQlCorsProperties corsProperties;
182182

183-
public GraphQlEndpointCorsConfiguration(GraphQlProperties graphql, GraphQlCorsProperties cors) {
184-
this.graphql = graphql;
185-
this.cors = cors;
183+
public GraphQlEndpointCorsConfiguration(GraphQlProperties graphQlProps, GraphQlCorsProperties corsProps) {
184+
this.graphQlProperties = graphQlProps;
185+
this.corsProperties = corsProps;
186186
}
187187

188188
@Override
189189
public void addCorsMappings(CorsRegistry registry) {
190-
CorsConfiguration configuration = cors.toCorsConfiguration();
190+
CorsConfiguration configuration = this.corsProperties.toCorsConfiguration();
191191
if (configuration != null) {
192-
registry.addMapping(graphql.getPath()).combine(configuration);
192+
registry.addMapping(this.graphQlProperties.getPath()).combine(configuration);
193193
}
194194
}
195195

spring-graphql-docs/src/docs/asciidoc/boot-starter.adoc

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -172,9 +172,33 @@ Declare a `ThreadLocalAccessor` bean to assist with the propagation of `ThreadLo
172172
values of interest in <<index.adoc#execution-context-webmvc,Spring MVC>>.
173173

174174

175+
[[boot-graphql-cors]]
176+
== CORS
177+
178+
{spring-framework-ref-docs}/web.html#mvc-cors[Spring MVC] and
179+
{spring-framework-ref-docs}/web-reactive.html#webflux-cors[Spring WebFlux] support CORS
180+
(Cross-Origin Resource Sharing) requests. CORS is a critical part of the web config for
181+
GraphQL applications that are accessed from browsers using different domains.
182+
183+
The Boot starter supports the following CORS properties:
184+
185+
[source,properties,indent=0,subs="verbatim"]
186+
----
187+
spring.graphql.cors.allowed-origins=https://example.org # Comma-separated list of origins to allow. '*' allows all origins.
188+
spring.graphql.cors.allowed-origin-patterns= # Comma-separated list of origin patterns like 'https://*.example.com' to allow.
189+
spring.graphql.cors.allowed-methods=GET,POST # Comma-separated list of methods to allow. '*' allows all methods.
190+
spring.graphql.cors.allowed-headers= # Comma-separated list of headers to allow in a request. '*' allows all headers.
191+
spring.graphql.cors.exposed-headers= # Comma-separated list of headers to include in a response.
192+
spring.graphql.cors.allow-credentials= # Whether credentials are supported. When not set, credentials are not supported.
193+
spring.graphql.cors.max-age=1800s # How long the response from a pre-flight request can be cached by clients.
194+
----
195+
196+
TIP: For more information about the properties and their meaning, check out the
197+
{javadoc}/org/springframework/graphql/boot/GraphQlCorsProperties.html[GraphQlCorsProperties Javadoc].
198+
175199

176200
[[boot-graphql-exception-handling]]
177-
== Exception
201+
== Exceptions
178202

179203
Spring GraphQL enables applications to register one or more Spring
180204
`DataFetcherExceptionResolver` components that are invoked sequentially until one
@@ -232,30 +256,6 @@ spring.graphql.graphiql.path=/graphiql
232256
----
233257

234258

235-
[[boot-graphql-cors]]
236-
== CORS configuration
237-
238-
Spring web frameworks all support CORS (Cross-Origin Resource Sharing), which is a critical part
239-
of your web configuration if your GraphQL API is meant to be accessed by browsers using different domains.
240-
241-
You can configure CORS support with properties:
242-
243-
[source,properties,indent=0,subs="verbatim"]
244-
----
245-
spring.graphql.cors.allowed-origins=https://example.org # Comma-separated list of origins to allow. '*' allows all origins.
246-
spring.graphql.cors.allowed-origin-patterns= # Comma-separated list of origin patterns like 'https://*.example.com' to allow.
247-
spring.graphql.cors.allowed-methods=GET,POST # Comma-separated list of methods to allow. '*' allows all methods.
248-
spring.graphql.cors.allowed-headers= # Comma-separated list of headers to allow in a request. '*' allows all headers.
249-
spring.graphql.cors.exposed-headers= # Comma-separated list of headers to include in a response.
250-
spring.graphql.cors.allow-credentials= # Whether credentials are supported. When not set, credentials are not supported.
251-
spring.graphql.cors.max-age=1800s # How long the response from a pre-flight request can be cached by clients.
252-
----
253-
254-
TIP: For more information about the properties and their meaning, check out the {javadoc}/org/springframework/graphql/boot/GraphQlCorsProperties.html[GraphQlCorsProperties Javadoc].
255-
256-
You can also learn more about CORS and Spring support in {spring-framework-ref-docs}/web.html#mvc-cors[Spring MVC] and
257-
{spring-framework-ref-docs}/web-reactive.html#webflux-cors[Spring WebFlux].
258-
259259
[[boot-graphql-metrics]]
260260
== Metrics
261261

0 commit comments

Comments
 (0)