Skip to content

Commit

Permalink
Add a basic health check to the router (apollographql#252)
Browse files Browse the repository at this point in the history
* Add a basic health check to the router

Provide a health check endpoint which behaves in the same way as the
health check on the gateway.

At this point in time it always returns pass because we don't have a
different health status to set.

resolves: apollographql#54
  • Loading branch information
garypen authored Dec 9, 2021
1 parent 7b3f919 commit 7afbd7d
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
source: apollo-router/src/warp_http_server_factory.rs
expression: "String::from_utf8_lossy(res.body())"

---
"{\"status\":\"pass\"}"
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
source: apollo-router/src/warp_http_server_factory.rs
expression: "hdrs[\"content-type\"].to_str().unwrap()"

---
application/json
50 changes: 49 additions & 1 deletion apollo-router/src/warp_http_server_factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use bytes::Bytes;
use futures::{channel::oneshot, prelude::*};
use hyper::server::conn::Http;
use opentelemetry::propagation::Extractor;
use std::collections::HashMap;
use std::pin::Pin;
use std::sync::Arc;
use tokio::net::TcpListener;
Expand Down Expand Up @@ -61,7 +62,8 @@ impl HttpServerFactory for WarpHttpServerFactory {
.map(tracing::Dispatch::new)
.unwrap_or_default();

let routes = get_graphql_request_or_redirect(Arc::clone(&router))
let routes = get_health_request()
.or(get_graphql_request_or_redirect(Arc::clone(&router)))
.or(post_graphql_request(router))
.with(cors);

Expand Down Expand Up @@ -229,6 +231,19 @@ fn redirect_to_studio(host: Option<Authority>) -> Box<dyn Reply> {
}
}

fn get_health_request() -> impl Filter<Extract = (Box<dyn Reply>,), Error = Rejection> + Clone {
warp::get()
.and(warp::path(".well-known"))
.and(warp::path("apollo"))
.and(warp::path("server-health"))
.and_then(move || async {
let mut result = HashMap::new();
result.insert("status", "pass");
let reply = Box::new(warp::reply::json(&result)) as Box<dyn Reply>;
Ok::<_, Rejection>(reply)
})
}

fn post_graphql_request<Router, PreparedQuery>(
router: Arc<Router>,
) -> impl Filter<Extract = (Box<dyn Reply>,), Error = Rejection> + Clone
Expand Down Expand Up @@ -337,6 +352,7 @@ impl<'a> Extractor for HeaderMapCarrier<'a> {
mod tests {
use super::*;
use crate::configuration::Cors;
use insta::{assert_json_snapshot, assert_snapshot};
use mockall::{mock, predicate::*};
use reqwest::header::{
ACCEPT, ACCESS_CONTROL_ALLOW_HEADERS, ACCESS_CONTROL_ALLOW_METHODS,
Expand Down Expand Up @@ -676,4 +692,36 @@ mod tests {
.iter()
.for_each(|accepts| assert!(!prefers_html(accepts.to_string())));
}

#[test(tokio::test)]
async fn it_provides_health_status_body() -> Result<(), FederatedServerError> {
let filter = get_health_request();

let res = warp::test::request()
.path("/.well-known/apollo/server-health")
.reply(&filter)
.await;

assert_eq!(res.status(), 200);
assert_json_snapshot!(String::from_utf8_lossy(res.body()));

Ok(())
}

#[test(tokio::test)]
async fn it_provides_health_status_header() -> Result<(), FederatedServerError> {
let filter = get_health_request();

let res = warp::test::request()
.path("/.well-known/apollo/server-health")
.reply(&filter)
.await;

let hdrs = res.headers();

assert_eq!(res.status(), 200);
assert_snapshot!(hdrs["content-type"].to_str().unwrap());

Ok(())
}
}

0 comments on commit 7afbd7d

Please sign in to comment.