Skip to content

Commit b65d61a

Browse files
smyrickShane Myrick
andauthored
Generate context with suspend and nullable in subscriptions (#1053)
* Generate context with suspend and nullable in subscriptions * Update tests * Do not cache null context for subscriptions * Rename internal methods * WIP * Update subsctiption javadocs * Use expression body * Update docs for context Co-authored-by: Shane Myrick <[email protected]>
1 parent 46807b8 commit b65d61a

File tree

28 files changed

+210
-200
lines changed

28 files changed

+210
-200
lines changed

examples/build.gradle.kts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ subprojects {
4040

4141
val kotlinVersion: String by project
4242
val junitVersion: String by project
43+
val kotlinCoroutinesVersion: String by project
4344

4445
val detektVersion: String by project
4546
val ktlintVersion: String by project
@@ -50,6 +51,8 @@ subprojects {
5051

5152
dependencies {
5253
implementation(kotlin("stdlib", kotlinVersion))
54+
implementation(kotlin("reflect", kotlinVersion))
55+
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:$kotlinCoroutinesVersion")
5356
testImplementation(kotlin("test-junit5", kotlinVersion))
5457
testImplementation("org.junit.jupiter:junit-jupiter-api:$junitVersion")
5558
testImplementation("org.junit.jupiter:junit-jupiter-engine:$junitVersion")

examples/server/ktor-server/src/main/kotlin/com/expediagroup/graphql/examples/server/ktor/KtorGraphQLContextFactory.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import io.ktor.request.ApplicationRequest
2525
*/
2626
class KtorGraphQLContextFactory : GraphQLContextFactory<AuthorizedContext, ApplicationRequest> {
2727

28-
override fun generateContext(request: ApplicationRequest): AuthorizedContext {
28+
override suspend fun generateContext(request: ApplicationRequest): AuthorizedContext {
2929
val loggedInUser = User(
3030
email = "[email protected]",
3131
firstName = "Someone",

examples/server/spring-server/src/main/kotlin/com/expediagroup/graphql/examples/server/spring/context/MyGraphQLContext.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,14 @@ import org.springframework.web.reactive.socket.WebSocketSession
2424
* Simple [GraphQLContext] that holds extra value and the [ServerRequest]
2525
*/
2626
class MyGraphQLContext(
27-
val myCustomValue: String,
28-
val request: ServerRequest
27+
val request: ServerRequest,
28+
val myCustomValue: String
2929
) : GraphQLContext
3030

3131
/**
3232
* Simple [GraphQLContext] that holds extra value and the [WebSocketSession]
3333
*/
3434
class MySubscriptionGraphQLContext(
3535
val request: WebSocketSession,
36-
var subscriptionValue: String? = null
36+
var auth: String? = null
3737
) : GraphQLContext

examples/server/spring-server/src/main/kotlin/com/expediagroup/graphql/examples/server/spring/context/MyGraphQLContextFactory.kt

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,20 @@ import org.springframework.web.reactive.socket.WebSocketSession
2929
@Component
3030
class MyGraphQLContextFactory : SpringGraphQLContextFactory<MyGraphQLContext>() {
3131

32-
override fun generateContext(request: ServerRequest): MyGraphQLContext = MyGraphQLContext(
33-
myCustomValue = request.headers().firstHeader("MyHeader") ?: "defaultContext",
34-
request = request
32+
override suspend fun generateContext(request: ServerRequest): MyGraphQLContext = MyGraphQLContext(
33+
request = request,
34+
myCustomValue = request.headers().firstHeader("MyHeader") ?: "defaultContext"
3535
)
3636
}
3737

38+
/**
39+
* [GraphQLContextFactory] that generates [MySubscriptionGraphQLContext] that will be available when processing subscription operations.
40+
*/
3841
@Component
3942
class MySubscriptionGraphQLContextFactory : SpringSubscriptionGraphQLContextFactory<MySubscriptionGraphQLContext>() {
4043

41-
override fun generateContext(request: WebSocketSession): MySubscriptionGraphQLContext = MySubscriptionGraphQLContext(
44+
override suspend fun generateContext(request: WebSocketSession): MySubscriptionGraphQLContext = MySubscriptionGraphQLContext(
4245
request = request,
43-
subscriptionValue = null
46+
auth = null
4447
)
4548
}

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

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@ package com.expediagroup.graphql.examples.server.spring.execution
1919
import com.expediagroup.graphql.examples.server.spring.context.MySubscriptionGraphQLContext
2020
import com.expediagroup.graphql.generator.execution.GraphQLContext
2121
import com.expediagroup.graphql.server.spring.subscriptions.ApolloSubscriptionHooks
22-
import kotlinx.coroutines.reactor.mono
2322
import org.springframework.web.reactive.socket.WebSocketSession
24-
import reactor.core.publisher.Mono
2523

2624
/**
2725
* A simple implementation of Apollo Subscription Lifecycle Events.
@@ -31,12 +29,11 @@ class MySubscriptionHooks : ApolloSubscriptionHooks {
3129
override fun onConnect(
3230
connectionParams: Map<String, String>,
3331
session: WebSocketSession,
34-
graphQLContext: GraphQLContext
35-
): Mono<GraphQLContext> = mono {
36-
if (graphQLContext is MySubscriptionGraphQLContext) {
37-
val bearer = connectionParams["Authorization"] ?: "none"
38-
graphQLContext.subscriptionValue = bearer
32+
graphQLContext: GraphQLContext?
33+
): GraphQLContext? {
34+
if (graphQLContext != null && graphQLContext is MySubscriptionGraphQLContext) {
35+
graphQLContext.auth = connectionParams["Authorization"]
3936
}
40-
graphQLContext
37+
return graphQLContext
4138
}
4239
}

examples/server/spring-server/src/main/kotlin/com/expediagroup/graphql/examples/server/spring/subscriptions/SimpleSubscription.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,5 +82,5 @@ class SimpleSubscription : Subscription {
8282

8383
@GraphQLDescription("Returns a value from the subscription context")
8484
fun subscriptionContext(myGraphQLContext: MySubscriptionGraphQLContext): Flux<String> =
85-
Flux.just(myGraphQLContext.subscriptionValue ?: "", "value 2", "value3")
85+
Flux.just(myGraphQLContext.auth ?: "no-auth")
8686
}

generator/graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/execution/FunctionDataFetcher.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ open class FunctionDataFetcher(
5959
* Invoke a suspend function or blocking function, passing in the [target] if not null or default to using the source from the environment.
6060
*/
6161
override fun get(environment: DataFetchingEnvironment): Any? {
62-
val instance = target ?: environment.getSource<Any?>()
62+
val instance: Any? = target ?: environment.getSource<Any?>()
6363
val instanceParameter = fn.instanceParameter
6464

6565
return if (instance != null && instanceParameter != null) {

generator/graphql-kotlin-schema-generator/src/main/kotlin/com/expediagroup/graphql/generator/execution/GraphQLContext.kt

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,8 @@
1616

1717
package com.expediagroup.graphql.generator.execution
1818

19-
import java.util.concurrent.ConcurrentHashMap
20-
import java.util.concurrent.ConcurrentMap
21-
2219
/**
2320
* Marker interface to indicate that the implementing class should be considered
2421
* as the GraphQL context. This means the implementing class will not appear in the schema.
2522
*/
2623
interface GraphQLContext
27-
28-
/**
29-
* Default [GraphQLContext] that can be used if there is none provided. Exposes generic concurrent hash map
30-
* that can be populated with custom data.
31-
*/
32-
class DefaultGraphQLContext : GraphQLContext {
33-
val contents: ConcurrentMap<Any, Any> = ConcurrentHashMap()
34-
}

servers/graphql-kotlin-server/src/main/kotlin/com/expediagroup/graphql/server/execution/GraphQLContextFactory.kt

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package com.expediagroup.graphql.server.execution
1818

19-
import com.expediagroup.graphql.generator.execution.DefaultGraphQLContext
2019
import com.expediagroup.graphql.generator.execution.GraphQLContext
2120

2221
/**
@@ -28,12 +27,5 @@ interface GraphQLContextFactory<out Context : GraphQLContext, Request> {
2827
* Generate GraphQL context based on the incoming request and the corresponding response.
2928
* If no context should be generated and used in the request, return null.
3029
*/
31-
fun generateContext(request: Request): Context?
32-
}
33-
34-
/**
35-
* Default context factory that generates GraphQL context with empty concurrent map that can store any elements.
36-
*/
37-
class DefaultGraphQLContextFactory<T> : GraphQLContextFactory<DefaultGraphQLContext, T> {
38-
override fun generateContext(request: T) = DefaultGraphQLContext()
30+
suspend fun generateContext(request: Request): Context?
3931
}

servers/graphql-kotlin-server/src/main/kotlin/com/expediagroup/graphql/server/extensions/requestExtensions.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package com.expediagroup.graphql.server.extensions
1818

19-
import com.expediagroup.graphql.generator.execution.DefaultGraphQLContext
2019
import com.expediagroup.graphql.types.GraphQLRequest
2120
import graphql.ExecutionInput
2221
import org.dataloader.DataLoaderRegistry
@@ -29,6 +28,6 @@ fun GraphQLRequest.toExecutionInput(graphQLContext: Any? = null, dataLoaderRegis
2928
.query(this.query)
3029
.operationName(this.operationName)
3130
.variables(this.variables ?: emptyMap())
32-
.context(graphQLContext ?: DefaultGraphQLContext())
31+
.context(graphQLContext)
3332
.dataLoaderRegistry(dataLoaderRegistry ?: DataLoaderRegistry())
3433
.build()

0 commit comments

Comments
 (0)