Skip to content

Commit

Permalink
feat: expose config through admin api
Browse files Browse the repository at this point in the history
  • Loading branch information
meskill committed Oct 3, 2024
1 parent aab7e07 commit 4c78a4e
Show file tree
Hide file tree
Showing 9 changed files with 149 additions and 2 deletions.
11 changes: 11 additions & 0 deletions generated/.tailcallrc.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,10 @@ set of server configurations. It dictates how the server behaves and helps tune
for various use-cases.
"""
directive @server(
"""
Control private admin API settings
"""
admin: Admin
"""
`apolloTracing` exposes GraphQL query performance data, including execution time
of queries and individual resolvers.
Expand Down Expand Up @@ -576,6 +580,13 @@ input Schema {
Enum: [String!]
}

input Admin {
"""
TCP port on which the admin api will be available
"""
port: Int!
}

"""
Type to configure Cross-Origin Resource Sharing (CORS) for a server.
"""
Expand Down
25 changes: 25 additions & 0 deletions generated/.tailcallrc.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,20 @@
},
"additionalProperties": false
},
"Admin": {
"type": "object",
"required": [
"port"
],
"properties": {
"port": {
"description": "TCP port on which the admin api will be available",
"type": "integer",
"format": "uint16",
"minimum": 1.0
}
}
},
"Alias": {
"description": "The @alias directive indicates that aliases of one enum value.",
"type": "object",
Expand Down Expand Up @@ -1004,6 +1018,17 @@
"description": "The `@server` directive, when applied at the schema level, offers a comprehensive set of server configurations. It dictates how the server behaves and helps tune tailcall for various use-cases.",
"type": "object",
"properties": {
"admin": {
"description": "Control private admin API settings",
"anyOf": [
{
"$ref": "#/definitions/Admin"
},
{
"type": "null"
}
]
},
"apolloTracing": {
"description": "`apolloTracing` exposes GraphQL query performance data, including execution time of queries and individual resolvers.",
"type": [
Expand Down
11 changes: 11 additions & 0 deletions src/cli/server/admin_server/graphql.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use async_graphql::SimpleObject;

#[derive(SimpleObject)]

Check warning on line 3 in src/cli/server/admin_server/graphql.rs

View check run for this annotation

Codecov / codecov/patch

src/cli/server/admin_server/graphql.rs#L3

Added line #L3 was not covered by tests
pub struct Config {
pub sdl: String,
}

#[derive(SimpleObject)]

Check warning on line 8 in src/cli/server/admin_server/graphql.rs

View check run for this annotation

Codecov / codecov/patch

src/cli/server/admin_server/graphql.rs#L8

Added line #L8 was not covered by tests
pub struct Query {
pub config: Config,
}
4 changes: 4 additions & 0 deletions src/cli/server/admin_server/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
mod graphql;
mod server;

pub use server::AdminServer;
75 changes: 75 additions & 0 deletions src/cli/server/admin_server/server.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
use std::net::SocketAddr;

use anyhow::Result;
use async_graphql::{EmptyMutation, EmptySubscription, Request, Schema};
use http::{Method, Response, StatusCode};
use hyper::service::{make_service_fn, service_fn};
use hyper::Server;

use super::graphql::{Config, Query};
use crate::core::async_graphql_hyper::GraphQLResponse;
use crate::core::blueprint::Blueprint;
use crate::core::config::ConfigModule;
use crate::core::Errata;

#[derive(Debug)]
pub struct AdminServer {
addr: SocketAddr,
sdl: String,
}

impl AdminServer {
pub fn new(config_module: &ConfigModule) -> Result<Option<Self>> {
if let Some(admin) = config_module.server.admin.as_ref() {
let blueprint = Blueprint::try_from(config_module).map_err(Errata::from)?;
let sdl = crate::core::document::print(config_module.config().into());
let addr = (blueprint.server.hostname, admin.port.get()).into();

Ok(Some(Self { addr, sdl }))

Check warning on line 28 in src/cli/server/admin_server/server.rs

View check run for this annotation

Codecov / codecov/patch

src/cli/server/admin_server/server.rs#L22-L28

Added lines #L22 - L28 were not covered by tests
} else {
Ok(None)

Check warning on line 30 in src/cli/server/admin_server/server.rs

View check run for this annotation

Codecov / codecov/patch

src/cli/server/admin_server/server.rs#L30

Added line #L30 was not covered by tests
}
}

Check warning on line 32 in src/cli/server/admin_server/server.rs

View check run for this annotation

Codecov / codecov/patch

src/cli/server/admin_server/server.rs#L32

Added line #L32 was not covered by tests

pub async fn start(self) -> Result<()> {
let server = Server::try_bind(&self.addr)?;
let config = Config { sdl: self.sdl };
let query = Query { config };
let schema = Schema::new(query, EmptyMutation, EmptySubscription);

server
.serve(make_service_fn(|_| {
let schema = schema.clone();
async move {
Result::<_>::Ok(service_fn(move |req| {
let (parts, body) = req.into_parts();
let schema = schema.clone();

Check warning on line 46 in src/cli/server/admin_server/server.rs

View check run for this annotation

Codecov / codecov/patch

src/cli/server/admin_server/server.rs#L34-L46

Added lines #L34 - L46 were not covered by tests

async move {
match parts.method {
Method::POST if parts.uri.path() == "/graphql" => {
let body = hyper::body::to_bytes(body).await?;
let request: Request = serde_json::from_slice(&body)?;

Check warning on line 52 in src/cli/server/admin_server/server.rs

View check run for this annotation

Codecov / codecov/patch

src/cli/server/admin_server/server.rs#L48-L52

Added lines #L48 - L52 were not covered by tests

let res = schema.execute(request).await;
let res = GraphQLResponse::from(res);

Result::<_>::Ok(res.into_response()?)

Check warning on line 57 in src/cli/server/admin_server/server.rs

View check run for this annotation

Codecov / codecov/patch

src/cli/server/admin_server/server.rs#L54-L57

Added lines #L54 - L57 were not covered by tests
}
_ => {
let mut response = Response::default();

*response.status_mut() = StatusCode::NOT_FOUND;

Result::<_>::Ok(response)

Check warning on line 64 in src/cli/server/admin_server/server.rs

View check run for this annotation

Codecov / codecov/patch

src/cli/server/admin_server/server.rs#L60-L64

Added lines #L60 - L64 were not covered by tests
}
}
}
}))
}
}))
.await?;

Check warning on line 71 in src/cli/server/admin_server/server.rs

View check run for this annotation

Codecov / codecov/patch

src/cli/server/admin_server/server.rs#L67-L71

Added lines #L67 - L71 were not covered by tests

Ok(())
}

Check warning on line 74 in src/cli/server/admin_server/server.rs

View check run for this annotation

Codecov / codecov/patch

src/cli/server/admin_server/server.rs#L73-L74

Added lines #L73 - L74 were not covered by tests
}
9 changes: 8 additions & 1 deletion src/cli/server/http_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::sync::Arc;
use anyhow::Result;
use tokio::sync::oneshot::{self};

use super::admin_server::AdminServer;
use super::http_1::start_http_1;
use super::http_2::start_http_2;
use super::server_config::ServerConfig;
Expand Down Expand Up @@ -53,7 +54,13 @@ impl Server {
.enable_all()
.build()?;

let result = runtime.spawn(async { self.start().await }).await?;
let admin_api = AdminServer::new(&self.config_module)?;

Check warning on line 57 in src/cli/server/http_server.rs

View check run for this annotation

Codecov / codecov/patch

src/cli/server/http_server.rs#L57

Added line #L57 was not covered by tests

if let Some(admin_api) = admin_api {
runtime.spawn(admin_api.start());
}

Check warning on line 61 in src/cli/server/http_server.rs

View check run for this annotation

Codecov / codecov/patch

src/cli/server/http_server.rs#L59-L61

Added lines #L59 - L61 were not covered by tests

let result = runtime.spawn(self.start()).await?;

Check warning on line 63 in src/cli/server/http_server.rs

View check run for this annotation

Codecov / codecov/patch

src/cli/server/http_server.rs#L63

Added line #L63 was not covered by tests
runtime.shutdown_background();

result
Expand Down
1 change: 1 addition & 0 deletions src/cli/server/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod admin_server;
pub mod http_1;
pub mod http_2;
pub mod http_server;
Expand Down
12 changes: 12 additions & 0 deletions src/core/config/server.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::collections::{BTreeMap, BTreeSet};
use std::num::NonZeroU16;

use derive_getters::Getters;
use schemars::JsonSchema;
Expand Down Expand Up @@ -130,6 +131,10 @@ pub struct Server {
/// - graphQL: "/graphql" If not specified, these default values will be
/// used.
pub routes: Option<Routes>,

/// Control private admin API settings
#[serde(default, skip_serializing_if = "is_default")]
pub admin: Option<Admin>,
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, MergeRight, JsonSchema, Getters)]
Expand Down Expand Up @@ -184,6 +189,13 @@ pub enum HttpVersion {
HTTP2,
}

#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, Clone, schemars::JsonSchema, MergeRight)]
#[serde(rename_all = "camelCase")]
pub struct Admin {
/// TCP port on which the admin api will be available
pub port: NonZeroU16,
}

impl Server {
pub fn enable_apollo_tracing(&self) -> bool {
self.apollo_tracing.unwrap_or(false)
Expand Down
3 changes: 2 additions & 1 deletion src/core/primitive.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::marker::PhantomData;
use std::num::NonZeroU64;
use std::num::{NonZeroU16, NonZeroU64};

use crate::core::merge_right::MergeRight;

Expand All @@ -16,6 +16,7 @@ impl Primitive for i8 {}
impl Primitive for NonZeroU64 {}
impl Primitive for String {}
impl Primitive for u16 {}
impl Primitive for NonZeroU16 {}
impl Primitive for u32 {}
impl Primitive for u64 {}
impl Primitive for u8 {}
Expand Down

0 comments on commit 4c78a4e

Please sign in to comment.