Skip to content

Commit 3e7fee7

Browse files
dariuszkucsmyrick
authored andcommitted
[spring-server] make ContextWebFilter conditionally created (#458)
ContextWebFilter is now an open class so it can be easily extended. Default implementation is now conditionally created. Resolves: #452
1 parent 066c0ea commit 3e7fee7

File tree

4 files changed

+26
-7
lines changed

4 files changed

+26
-7
lines changed

docs/server/spring-beans.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ can be customized by providing custom beans in your application context. See sec
2020

2121
| Bean | Description |
2222
|:-------------------------------|:------------|
23+
| ContextWebFilter | Default web filter that populates GraphQL context in the reactor subscriber context. |
2324
| DataFetcherExceptionHandler | GraphQL exception handler used from the various execution strategies, defaults to [KotlinDataFetcherExceptionHandler](https://github.com/ExpediaGroup/graphql-kotlin/blob/master/graphql-kotlin-spring-server/src/main/kotlin/com/expediagroup/graphql/spring/exception/KotlinDataFetcherExceptionHandler.kt). |
2425
| GraphQL | GraphQL query execution engine generated using `GraphQLSchema` with default async execution strategies. GraphQL engine can be customized by optionally providing a list of [Instrumentation](https://www.graphql-java.com/documentation/v13/instrumentation/) beans (which can be ordered by implementing Spring Ordered interface), [ExecutionIdProvider](https://github.com/graphql-java/graphql-java/blob/master/src/main/java/graphql/execution/ExecutionIdProvider.java) and [PreparsedDocumentProvider](https://github.com/graphql-java/graphql-java/blob/master/src/main/java/graphql/execution/preparsed/PreparsedDocumentProvider.java) in the application context. |
2526
| DataLoaderRegistryFactory | Factory used to create DataLoaderRegistry instance per query execution. See [graphql-java documentation](https://www.graphql-java.com/documentation/v13/batching/) for more details. |
@@ -30,7 +31,6 @@ can be customized by providing custom beans in your application context. See sec
3031

3132
The following beans are currently automatically created and cannot be disabled:
3233

33-
* Web filter for generating and populating GraphQL context
3434
* Default routes for GraphQL queries/mutations and SDL endpoint
3535
* Default route for [Prisma Labs Playground](https://github.com/prisma-labs/graphql-playground), created only if playground is enabled
3636
* Default `ApolloSubscriptionProtocolHandler` for handling GraphQL subscriptions, created only if `Subscription` bean is available in the context

graphql-kotlin-spring-server/src/main/kotlin/com/expediagroup/graphql/spring/GraphQLAutoConfiguration.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ import org.springframework.context.annotation.Bean
4040
import org.springframework.context.annotation.Configuration
4141
import org.springframework.context.annotation.Import
4242
import org.springframework.core.Ordered
43-
import org.springframework.web.server.WebFilter
4443
import java.util.Optional
4544

4645
/**
@@ -119,8 +118,9 @@ class GraphQLAutoConfiguration {
119118
fun graphQLContextFactory(): GraphQLContextFactory<*> = EmptyContextFactory
120119

121120
@Bean
121+
@ConditionalOnMissingBean
122122
fun contextWebFilter(
123123
config: GraphQLConfigurationProperties,
124124
graphQLContextFactory: GraphQLContextFactory<*>
125-
): WebFilter = ContextWebFilter(config, graphQLContextFactory)
125+
): ContextWebFilter = ContextWebFilter(config, graphQLContextFactory)
126126
}

graphql-kotlin-spring-server/src/main/kotlin/com/expediagroup/graphql/spring/execution/ContextWebFilter.kt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ const val GRAPHQL_CONTEXT_FILTER_ODER = 0
3333
/**
3434
* Default web filter that populates GraphQL context in the reactor subscriber context.
3535
*/
36-
class ContextWebFilter(config: GraphQLConfigurationProperties, private val contextFactory: GraphQLContextFactory<Any>) : WebFilter, Ordered {
37-
private val graphQLRoute = "/${config.endpoint}"
38-
private val subscriptionsRoute = "/${config.subscriptions.endpoint}"
36+
open class ContextWebFilter(config: GraphQLConfigurationProperties, private val contextFactory: GraphQLContextFactory<Any>) : WebFilter, Ordered {
37+
private val graphQLRoute = enforceAbsolutePath(config.endpoint)
38+
private val subscriptionsRoute = enforceAbsolutePath(config.subscriptions.endpoint)
3939

4040
@Suppress("ForbiddenVoid")
4141
override fun filter(exchange: ServerWebExchange, chain: WebFilterChain): Mono<Void> =
@@ -51,6 +51,8 @@ class ContextWebFilter(config: GraphQLConfigurationProperties, private val conte
5151

5252
override fun getOrder(): Int = GRAPHQL_CONTEXT_FILTER_ODER
5353

54-
internal fun isApplicable(path: String): Boolean =
54+
open fun isApplicable(path: String): Boolean =
5555
graphQLRoute.equals(path, ignoreCase = true) || subscriptionsRoute.equals(path, ignoreCase = true)
56+
57+
private fun enforceAbsolutePath(path: String) = if (path.startsWith("/")) { path } else { "/$path" }
5658
}

graphql-kotlin-spring-server/src/test/kotlin/com/expediagroup/graphql/spring/SchemaConfigurationTest.kt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package com.expediagroup.graphql.spring
1818

1919
import com.expediagroup.graphql.SchemaGeneratorConfig
2020
import com.expediagroup.graphql.TopLevelObject
21+
import com.expediagroup.graphql.spring.execution.ContextWebFilter
2122
import com.expediagroup.graphql.spring.execution.DataLoaderRegistryFactory
2223
import com.expediagroup.graphql.spring.execution.GraphQLContextFactory
2324
import com.expediagroup.graphql.spring.execution.QueryHandler
@@ -75,6 +76,7 @@ class SchemaConfigurationTest {
7576

7677
assertThat(ctx).hasSingleBean(DataLoaderRegistryFactory::class.java)
7778
assertThat(ctx).hasSingleBean(QueryHandler::class.java)
79+
assertThat(ctx).hasSingleBean(ContextWebFilter::class.java)
7880
assertThat(ctx).hasSingleBean(GraphQLContextFactory::class.java)
7981
}
8082
}
@@ -85,6 +87,7 @@ class SchemaConfigurationTest {
8587
.withPropertyValues("graphql.packages=com.expediagroup.graphql.spring")
8688
.run { ctx ->
8789
val customConfiguration = ctx.getBean(CustomConfiguration::class.java)
90+
val graphQLProperties = ctx.getBean(GraphQLConfigurationProperties::class.java)
8891

8992
assertThat(ctx).hasSingleBean(SchemaGeneratorConfig::class.java)
9093
assertThat(ctx).getBean(SchemaGeneratorConfig::class.java)
@@ -104,6 +107,10 @@ class SchemaConfigurationTest {
104107

105108
assertThat(ctx).hasSingleBean(QueryHandler::class.java)
106109

110+
assertThat(ctx).hasSingleBean(ContextWebFilter::class.java)
111+
assertThat(ctx).getBean(ContextWebFilter::class.java)
112+
.isSameAs(customConfiguration.myCustomContextWebFilter(graphQLProperties, customConfiguration.myCustomContextFactory()))
113+
107114
assertThat(ctx).hasSingleBean(GraphQLContextFactory::class.java)
108115
assertThat(ctx).getBean(GraphQLContextFactory::class.java)
109116
.isSameAs(customConfiguration.myCustomContextFactory())
@@ -152,6 +159,16 @@ class SchemaConfigurationTest {
152159

153160
@Bean
154161
fun myDataLoaderRegistryFactory(): DataLoaderRegistryFactory = mockk()
162+
163+
@Bean
164+
fun myCustomContextWebFilter(
165+
config: GraphQLConfigurationProperties,
166+
graphQLContextFactory: GraphQLContextFactory<*>
167+
): ContextWebFilter = object : ContextWebFilter(config, graphQLContextFactory) {
168+
private val regex = config.endpoint.toRegex()
169+
170+
override fun isApplicable(path: String): Boolean = regex.matches(path)
171+
}
155172
}
156173

157174
class BasicQuery : Query {

0 commit comments

Comments
 (0)