-
Notifications
You must be signed in to change notification settings - Fork 65
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: update subs callback to SpringBoot 3.3 (#404)
- Loading branch information
1 parent
2b17eaf
commit 028dd64
Showing
12 changed files
with
217 additions
and
390 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
107 changes: 107 additions & 0 deletions
107
...-callback/src/main/java/com/apollographql/subscription/CallbackWebGraphQLInterceptor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
package com.apollographql.subscription; | ||
|
||
import static com.apollographql.subscription.callback.SubscriptionCallback.parseSubscriptionCallbackExtension; | ||
import static com.apollographql.subscription.callback.SubscriptionCallbackHandler.SUBSCRIPTION_PROTOCOL_HEADER; | ||
import static com.apollographql.subscription.callback.SubscriptionCallbackHandler.SUBSCRIPTION_PROTOCOL_HEADER_VALUE; | ||
|
||
import com.apollographql.subscription.callback.SubscriptionCallbackHandler; | ||
import graphql.ExecutionResult; | ||
import graphql.GraphQLError; | ||
import org.apache.commons.logging.Log; | ||
import org.apache.commons.logging.LogFactory; | ||
import org.springframework.core.Ordered; | ||
import org.springframework.graphql.server.WebGraphQlInterceptor; | ||
import org.springframework.graphql.server.WebGraphQlRequest; | ||
import org.springframework.graphql.server.WebGraphQlResponse; | ||
import org.springframework.graphql.server.WebSocketGraphQlRequest; | ||
import org.springframework.graphql.support.DefaultExecutionGraphQlResponse; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.web.server.ResponseStatusException; | ||
import reactor.core.publisher.Mono; | ||
|
||
/** | ||
* Interceptor that provides support for Apollo Subscription Callback Protocol. This interceptor | ||
* defaults to {@link Ordered#LOWEST_PRECEDENCE} order as it should run last in chain to allow users | ||
* to still apply other interceptors that handle common stuff (e.g. extracting auth headers, etc). | ||
* You can override this behavior by specifying custom order. | ||
* | ||
* @see <a | ||
* href="https://www.apollographql.com/docs/router/executing-operations/subscription-callback-protocol">Subscription | ||
* Callback Protocol</a> | ||
*/ | ||
public class CallbackWebGraphQLInterceptor implements WebGraphQlInterceptor, Ordered { | ||
|
||
private static final Log logger = LogFactory.getLog(CallbackWebGraphQLInterceptor.class); | ||
|
||
private final SubscriptionCallbackHandler subscriptionCallbackHandler; | ||
private final int order; | ||
|
||
public CallbackWebGraphQLInterceptor(SubscriptionCallbackHandler subscriptionCallbackHandler) { | ||
this(subscriptionCallbackHandler, LOWEST_PRECEDENCE); | ||
} | ||
|
||
public CallbackWebGraphQLInterceptor( | ||
SubscriptionCallbackHandler subscriptionCallbackHandler, int order) { | ||
this.subscriptionCallbackHandler = subscriptionCallbackHandler; | ||
this.order = order; | ||
} | ||
|
||
@Override | ||
public Mono<WebGraphQlResponse> intercept(WebGraphQlRequest request, Chain chain) { | ||
// in order to correctly handle parsing of ANY requests (i.e. it is valid to define a | ||
// document with query fragments first) we would need to parse it which is a much heavier | ||
// operation, we may opt to do it in the future releases | ||
if (!isWebSocketRequest(request) && request.getDocument().startsWith("subscription")) { | ||
return parseSubscriptionCallbackExtension(request.getExtensions()) | ||
.flatMap( | ||
callback -> { | ||
if (logger.isDebugEnabled()) { | ||
logger.debug("Starting subscription using callback: " + callback); | ||
} | ||
return this.subscriptionCallbackHandler | ||
.handleSubscriptionUsingCallback(request, callback) | ||
.map(response -> callbackResponse(request, response)); | ||
}) | ||
.onErrorResume( | ||
(error) -> { | ||
if (logger.isErrorEnabled()) { | ||
logger.error("Unable to start subscription using callback protocol", error); | ||
} | ||
return Mono.error(new ResponseStatusException(HttpStatus.BAD_REQUEST)); | ||
}); | ||
} else { | ||
return chain.next(request); | ||
} | ||
} | ||
|
||
private boolean isWebSocketRequest(WebGraphQlRequest request) { | ||
return request instanceof WebSocketGraphQlRequest; | ||
} | ||
|
||
private WebGraphQlResponse callbackResponse( | ||
WebGraphQlRequest request, ExecutionResult callbackResult) { | ||
var callbackExecutionResponse = | ||
new DefaultExecutionGraphQlResponse(request.toExecutionInput(), callbackResult); | ||
var callbackGraphQLResponse = new WebGraphQlResponse(callbackExecutionResponse); | ||
callbackGraphQLResponse | ||
.getResponseHeaders() | ||
.add(SUBSCRIPTION_PROTOCOL_HEADER, SUBSCRIPTION_PROTOCOL_HEADER_VALUE); | ||
return callbackGraphQLResponse; | ||
} | ||
|
||
private WebGraphQlResponse errorCallbackResponse(WebGraphQlRequest request) { | ||
var errorCallbackResult = | ||
ExecutionResult.newExecutionResult() | ||
.addError( | ||
GraphQLError.newError() | ||
.message("Unable to start subscription using callback protocol") | ||
.build()) | ||
.build(); | ||
return callbackResponse(request, errorCallbackResult); | ||
} | ||
|
||
@Override | ||
public int getOrder() { | ||
return order; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
15 changes: 15 additions & 0 deletions
15
.../java/com/apollographql/subscription/exception/CallbackInitializationFailedException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package com.apollographql.subscription.exception; | ||
|
||
import com.apollographql.subscription.callback.SubscriptionCallback; | ||
|
||
/** Exception thrown when callback initialization fails. */ | ||
public class CallbackInitializationFailedException extends RuntimeException { | ||
|
||
public CallbackInitializationFailedException(SubscriptionCallback callback, int statusCode) { | ||
super( | ||
"Subscription callback failed initialization: " | ||
+ callback | ||
+ ", server responded with: " | ||
+ statusCode); | ||
} | ||
} |
Oops, something went wrong.