Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions juniper/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,13 @@ All user visible changes to `juniper` crate will be documented in this file. Thi
- Added `description` field to `ast::Operation`, `ast::Fragment` and `ast::VariableDefinition`. ([#1349], [graphql/graphql-spec#1170])
- Renamed `ast::VariableDefinitions` to `ast::VariablesDefinition`: ([#1353], [graphql/graphql-spec#916])
- Renamed `ast::Operation::variable_definitions` field to `variables_definition`.
- Added `extenstions` field to `http::GraphQLRequest`. ([#1356], [graphql/graphql-spec#976])
- Added `Ext` type parameter to `http::GraphQLRequest` and `http::GraphQLBatchRequest` defaulting to `Variables`. ([#1356], [graphql/graphql-spec#976])
- Changed `ScalarToken::String` to contain raw quoted and escaped `StringLiteral` (was unquoted but escaped string before). ([#1349])
- Added `LexerError::UnterminatedBlockString` variant. ([#1349])
- `http::GraphQLRequest`:
- Removed `new()` constructor in favor of constructing it directly. ([#1356])
- Removed deprecated `operation_name()` method in favor of direct `operation_name` field. ([#1356])

### Added

Expand Down Expand Up @@ -72,12 +77,14 @@ All user visible changes to `juniper` crate will be documented in this file. Thi
[#1353]: /../../pull/1353
[#1354]: /../../pull/1354
[#1355]: /../../pull/1355
[#1356]: /../../pull/1356
[graphql/graphql-spec#525]: https://github.com/graphql/graphql-spec/pull/525
[graphql/graphql-spec#687]: https://github.com/graphql/graphql-spec/issues/687
[graphql/graphql-spec#805]: https://github.com/graphql/graphql-spec/pull/805
[graphql/graphql-spec#825]: https://github.com/graphql/graphql-spec/pull/825
[graphql/graphql-spec#849]: https://github.com/graphql/graphql-spec/pull/849
[graphql/graphql-spec#916]: https://github.com/graphql/graphql-spec/pull/916
[graphql/graphql-spec#976]: https://github.com/graphql/graphql-spec/pull/976
[graphql/graphql-spec#1040]: https://github.com/graphql/graphql-spec/pull/1040
[graphql/graphql-spec#1142]: https://github.com/graphql/graphql-spec/pull/1142
[graphql/graphql-spec#1170]: https://github.com/graphql/graphql-spec/pull/1170
Expand Down
90 changes: 89 additions & 1 deletion juniper/src/executor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,95 @@ pub trait FromContext<T> {
}

/// Marker trait for types that can act as context objects for `GraphQL` types.
pub trait Context {}
pub trait Context {
/// Consumes the provided [request `extensions`][0] into this [`Context`].
///
/// # Implementation
///
/// Default implementation does nothing.
///
/// This method should be implemented if a [`Context`] implementation wants to be populated with
/// [request `extensions`][0]. Since [request `extensions`][0] could be modeled as an arbitrary
/// type, the implementation should downcast to the desired type before use.
///
/// ```rust
/// # use juniper::{
/// # Context, DefaultScalarValue, EmptyMutation, EmptySubscription, RootNode,
/// # graphql_object, graphql_value, http::GraphQLRequest,
/// # };
/// # use serde::{Deserialize, Serialize};
/// # use serde_json::json;
/// #
/// #[derive(Deserialize, Serialize)]
/// #[serde(rename_all = "camelCase")]
/// struct CustomExtensions {
/// persisted_query: PersistedQueryExtensions,
/// }
///
/// #[derive(Deserialize, Serialize)]
/// #[serde(rename_all = "camelCase")]
/// struct PersistedQueryExtensions {
/// sha256_hash: Box<str>,
/// }
///
/// type CustomGraphQLRequest<S = DefaultScalarValue> = GraphQLRequest<S, CustomExtensions>;
///
/// #[derive(Default)]
/// struct CustomContext {
/// persisted_query_sha256_hash: Option<Box<str>>,
/// }
///
/// impl Context for CustomContext {
/// fn consume_request_extensions<T: 'static>(&mut self, extensions: &T) {
/// use juniper::AnyExt as _; // allows downcasting directly on types without `dyn`
///
/// if let Some(ext) = extensions.downcast_ref::<CustomExtensions>() {
/// self.persisted_query_sha256_hash =
/// Some(ext.persisted_query.sha256_hash.clone());
/// }
/// }
/// }
///
/// struct Query;
///
/// #[graphql_object]
/// impl Query {
/// fn is_persisted_query(context: &CustomContext) -> bool {
/// context.persisted_query_sha256_hash.is_some()
/// }
/// }
/// #
/// # type Schema = RootNode<
/// # Query, EmptyMutation<CustomContext>, EmptySubscription<CustomContext>,
/// # >;
/// #
/// # #[tokio::main]
/// # async fn main() {
/// # let request: CustomGraphQLRequest = serde_json::from_value(json!({
/// # "query": "{ isPersistedQuery }",
/// # "extensions": {
/// # "persistedQuery": {
/// # "sha256Hash":
/// # "c205cf782b5c43c3fc67b5233445b78fbea47b99a0302cf31bda2a8e2162e1e6",
/// # },
/// # },
/// # })).unwrap();
/// # let schema = Schema::new(Query, EmptyMutation::new(), EmptySubscription::new());
/// # let context = CustomContext::default();
/// #
/// # assert_eq!(
/// # request.execute(&schema, context).await.into_result(),
/// # Ok((graphql_value!({"isPersistedQuery": true}), vec![])),
/// # );
/// # }
/// ```
///
/// [0]: https://spec.graphql.org/September2025#sel-FANHLBBgBBvC0vW
fn consume_request_extensions<T: 'static>(&mut self, extensions: &T) {
_ = extensions;
}

}

impl<C: Context> Context for &C {}

Expand Down
Loading