Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enhancement(config api): Add graphql field to toggle graphql endpoint #19645

Merged
Merged
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
3 changes: 3 additions & 0 deletions changelog.d/graphql_endpoint_toggle.enhancement.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Added a boolean `graphql` field to the api configuration to allow disabling the graphql endpoint.

Note that the `playground` endpoint will now only be enabled if the `graphql` endpoint is also enabled.
neuronull marked this conversation as resolved.
Show resolved Hide resolved
29 changes: 18 additions & 11 deletions src/api/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use warp::{filters::BoxedFilter, http::Response, ws::Ws, Filter, Reply};

use super::{handler, schema, ShutdownTx};
use crate::{
config,
config::{self, api},
http::build_http_trace_layer,
internal_events::{SocketBindError, SocketMode},
topology,
Expand All @@ -38,7 +38,7 @@ impl Server {
running: Arc<AtomicBool>,
handle: &Handle,
) -> crate::Result<Self> {
let routes = make_routes(config.api.playground, watch_rx, running);
let routes = make_routes(config.api, watch_rx, running);

let (_shutdown, rx) = oneshot::channel();
// warp uses `tokio::spawn` and so needs us to enter the runtime context.
Expand Down Expand Up @@ -96,7 +96,7 @@ impl Server {
}

fn make_routes(
playground: bool,
api: api::Options,
watch_tx: topology::WatchRx,
running: Arc<AtomicBool>,
) -> BoxedFilter<(impl Reply,)> {
Expand All @@ -108,6 +108,7 @@ fn make_routes(
.and_then(handler::health);

// 404.
let not_found_graphql = warp::any().and_then(|| async { Err(warp::reject::not_found()) });
let not_found = warp::any().and_then(|| async { Err(warp::reject::not_found()) });

// GraphQL subscription handler. Creates a Warp WebSocket handler and for each connection,
Expand Down Expand Up @@ -140,16 +141,22 @@ fn make_routes(
// Handle GraphQL queries. Headers will first be parsed to determine whether the query is
// a subscription and if so, an attempt will be made to upgrade the connection to WebSockets.
// All other queries will fall back to the default HTTP handler.
let graphql_handler = warp::path("graphql").and(graphql_subscription_handler.or(
async_graphql_warp::graphql(schema::build_schema().finish()).and_then(
|(schema, request): (Schema<_, _, _>, Request)| async move {
Ok::<_, Infallible>(GraphQLResponse::from(schema.execute(request).await))
},
),
));
let graphql_handler = if api.graphql {
warp::path("graphql")
.and(graphql_subscription_handler.or(
async_graphql_warp::graphql(schema::build_schema().finish()).and_then(
|(schema, request): (Schema<_, _, _>, Request)| async move {
Ok::<_, Infallible>(GraphQLResponse::from(schema.execute(request).await))
},
),
))
.boxed()
} else {
not_found_graphql.boxed()
};

// Provide a playground for executing GraphQL queries/mutations/subscriptions.
let graphql_playground = if playground {
let graphql_playground = if api.playground && api.graphql {
warp::path("playground")
.map(move || {
Response::builder()
Expand Down
20 changes: 20 additions & 0 deletions src/config/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ pub struct Options {
/// Whether or not to expose the GraphQL playground on the API endpoint.
#[serde(default = "default_playground")]
pub playground: bool,

/// Whether or not the GraphQL endpoint is enabled
#[serde(default = "default_graphql", skip_serializing_if = "is_true")]
pub graphql: bool,
}

impl Default for Options {
Expand All @@ -27,10 +31,17 @@ impl Default for Options {
enabled: default_enabled(),
playground: default_playground(),
address: default_address(),
graphql: default_graphql(),
}
}
}

// serde passes struct fields as reference
sebastiantia marked this conversation as resolved.
Show resolved Hide resolved
#[allow(clippy::trivially_copy_pass_by_ref)]
const fn is_true(value: &bool) -> bool {
*value
}

const fn default_enabled() -> bool {
false
}
Expand All @@ -53,6 +64,10 @@ const fn default_playground() -> bool {
true
}

const fn default_graphql() -> bool {
true
}

impl Options {
pub fn merge(&mut self, other: Self) -> Result<(), String> {
// Merge options
Expand All @@ -78,6 +93,7 @@ impl Options {
address,
enabled: self.enabled | other.enabled,
playground: self.playground & other.playground,
graphql: self.graphql & other.graphql,
};

*self = options;
Expand All @@ -91,6 +107,7 @@ fn bool_merge() {
enabled: true,
address: None,
playground: false,
graphql: false,
};

a.merge(Options::default()).unwrap();
Expand All @@ -101,6 +118,7 @@ fn bool_merge() {
enabled: true,
address: default_address(),
playground: false,
graphql: false
}
);
}
Expand All @@ -112,6 +130,7 @@ fn bind_merge() {
enabled: true,
address: Some(address),
playground: true,
graphql: true,
};

a.merge(Options::default()).unwrap();
Expand All @@ -122,6 +141,7 @@ fn bind_merge() {
enabled: true,
address: Some(address),
playground: true,
graphql: true,
}
);
}
Expand Down
13 changes: 12 additions & 1 deletion website/cue/reference/api.cue
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,18 @@ api: {
description: """
Whether the [GraphQL Playground](\(urls.graphql_playground)) is enabled
for the API. The Playground is accessible via the `/playground` endpoint
of the address set using the `bind` parameter.
of the address set using the `bind` parameter. Note that the `playground`
endpoint will only be enabled if the `graphql` endpoint is also enabled.
"""
}
graphql: {
common: true
required: false
type: bool: default: true
description: """
Whether the endpoint for receiving and processing GraphQL queries is
enabled for the API. The endpoint is accessible via the `/graphql`
endpoint of the address set using the `bind` parameter.
"""
}
}
Expand Down
Loading