Skip to content

Commit

Permalink
Respond to review
Browse files Browse the repository at this point in the history
  • Loading branch information
jackkleeman committed Mar 29, 2023
1 parent 2b1cba9 commit 592a3ef
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 77 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ In order to change the log level, configure the [`RUST_LOG` env variable](https:
After the runtime is running, you can register a service running on `localhost:8080` via `curl`:

```shell
curl -X POST localhost:8081/endpoint/discover -H 'content-type: application/json' -d '{"uri": "http://localhost:8080"}'
curl -X POST localhost:8081/services/discover -H 'content-type: application/json' -d '{"uri": "http://localhost:8080"}'
```

This assumes that the runtime is running on `localhost:8081`.
Expand Down
17 changes: 14 additions & 3 deletions src/meta/src/rest_api/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,19 @@ use crate::service::MetaError;
pub enum MetaApiError {
#[error("The request field '{0}' is invalid. Reason: {1}")]
InvalidField(&'static str, String),
#[error("The requested {0} '{1}' does not exist")]
NotFound(&'static str, String),
#[error("The requested service '{0}' does not exist")]
ServiceNotFound(String),
#[error("The requested method '{method_name}' on service '{service_name}' does not exist")]
MethodNotFound {
service_name: String,
method_name: String,
},
#[error(transparent)]
Meta(#[from] MetaError),
}

impl MetaApiError {}

/// To format the error response body.
#[derive(Debug, Serialize)]
struct ErrorDescriptionResponse {
Expand All @@ -27,7 +34,11 @@ impl IntoResponse for MetaApiError {
fn into_response(self) -> Response {
let status_code = match &self {
MetaApiError::InvalidField(_, _) => StatusCode::BAD_REQUEST,
MetaApiError::NotFound(_, _) => StatusCode::NOT_FOUND,
MetaApiError::ServiceNotFound(_) => StatusCode::NOT_FOUND,
MetaApiError::MethodNotFound {
service_name: _,
method_name: _,
} => StatusCode::NOT_FOUND,
MetaApiError::Meta(MetaError::Discovery(desc_error)) if desc_error.is_user_error() => {
StatusCode::BAD_REQUEST
}
Expand Down
43 changes: 17 additions & 26 deletions src/meta/src/rest_api/methods.rs
Original file line number Diff line number Diff line change
@@ -1,71 +1,62 @@
use super::error::*;
use super::state::*;
use crate::rest_api::error::MetaApiError::NotFound;
use axum::extract::{Path, Query, State};
use axum::extract::{Path, State};
use axum::Json;
use serde::{Deserialize, Serialize};
use serde::Serialize;
use service_metadata::MethodDescriptorRegistry;
use std::sync::Arc;

#[derive(Debug, Deserialize)]
pub struct ListMethodsRequest {}

#[derive(Debug, Serialize)]
pub struct ListMethodsResponse {
methods: Vec<GetMethodResponse>,
pub struct ListServiceMethodsResponse {
methods: Vec<GetServiceMethodResponse>,
}

/// List discovered methods for service
pub async fn list_methods<S, M: MethodDescriptorRegistry>(
pub async fn list_service_methods<S, M: MethodDescriptorRegistry>(
State(state): State<Arc<RestEndpointState<S, M>>>,
Path(service_name): Path<String>,
Query(_): Query<ListMethodsRequest>,
) -> Result<Json<ListMethodsResponse>, MetaApiError> {
) -> Result<Json<ListServiceMethodsResponse>, MetaApiError> {
match state
.method_descriptor_registry()
.list_methods(service_name.as_str())
{
Some(methods) => Ok(ListMethodsResponse {
Some(methods) => Ok(ListServiceMethodsResponse {
methods: methods
.keys()
.map(|method_name| GetMethodResponse {
.map(|method_name| GetServiceMethodResponse {
service_name: service_name.clone(),
method_name: method_name.clone(),
})
.collect(),
}
.into()),
None => Err(NotFound("service", service_name)),
None => Err(MetaApiError::ServiceNotFound(service_name)),
}
}

#[derive(Debug, Deserialize)]
pub struct GetMethodRequest {}

#[derive(Debug, Serialize)]
pub struct GetMethodResponse {
pub struct GetServiceMethodResponse {
service_name: String,
method_name: String,
}

/// Get an method of a service
pub async fn get_method<S, M: MethodDescriptorRegistry>(
pub async fn get_service_method<S, M: MethodDescriptorRegistry>(
State(state): State<Arc<RestEndpointState<S, M>>>,
Path((service_name, method_name)): Path<(String, String)>,
Query(_): Query<GetMethodRequest>,
) -> Result<Json<GetMethodResponse>, MetaApiError> {
) -> Result<Json<GetServiceMethodResponse>, MetaApiError> {
let endpoint = state
.method_descriptor_registry()
.resolve_method_descriptor(service_name.as_str(), method_name.as_str());
match endpoint {
Some(_) => Ok(GetMethodResponse {
Some(_) => Ok(GetServiceMethodResponse {
service_name,
method_name,
}
.into()),
None => Err(NotFound(
"method",
format!("{}/{}", service_name, method_name),
)),
None => Err(MetaApiError::MethodNotFound {
service_name,
method_name,
}),
}
}
25 changes: 18 additions & 7 deletions src/meta/src/rest_api/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
//! This module implements the Meta API endpoint.

mod endpoints;
mod error;
mod methods;
mod services;
mod state;

use axum::error_handling::HandleErrorLayer;
Expand Down Expand Up @@ -50,13 +50,24 @@ impl MetaRestEndpoint {

// Setup the router
let meta_api = Router::new()
.route("/endpoint/discover", post(endpoints::discover_endpoint))
.route("/endpoint/", get(endpoints::list_endpoints))
.route("/endpoint/:endpoint", get(endpoints::get_endpoint))
.route("/endpoint/:endpoint/method/", get(methods::list_methods))
// deprecated url
.route(
"/endpoint/:endpoint/method/:method",
get(methods::get_method),
"/endpoint/discover",
post(services::discover_service_endpoint),
)
.route(
"/services/discover",
post(services::discover_service_endpoint),
)
.route("/services/", get(services::list_services))
.route("/services/:service", get(services::get_service))
.route(
"/services/:service/methods/",
get(methods::list_service_methods),
)
.route(
"/services/:service/methods/:method",
get(methods::get_service_method),
)
.with_state(shared_state)
.layer(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::error::*;
use super::state::*;
use axum::extract::{Path, Query, State};
use axum::extract::{Path, State};
use axum::http::Uri;
use axum::Json;
use hyper::http::{HeaderName, HeaderValue};
Expand All @@ -12,22 +12,22 @@ use std::sync::Arc;

#[serde_as]
#[derive(Debug, Deserialize)]
pub struct RegisterEndpointRequest {
pub struct RegisterServiceEndpointRequest {
#[serde_as(as = "serde_with::DisplayFromStr")]
pub uri: Uri,
pub additional_headers: Option<HashMap<String, String>>,
}

#[derive(Debug, Serialize)]
pub struct RegisterEndpointResponse {
pub struct RegisterServiceEndpointResponse {
services: Vec<String>,
}

/// Discover endpoint and return discovered endpoints.
pub async fn discover_endpoint<S: ServiceEndpointRegistry, M>(
pub async fn discover_service_endpoint<S: ServiceEndpointRegistry, M>(
State(state): State<Arc<RestEndpointState<S, M>>>,
Json(payload): Json<RegisterEndpointRequest>,
) -> Result<Json<RegisterEndpointResponse>, MetaApiError> {
Json(payload): Json<RegisterServiceEndpointRequest>,
) -> Result<Json<RegisterServiceEndpointResponse>, MetaApiError> {
let headers = payload
.additional_headers
.unwrap_or_default()
Expand All @@ -43,61 +43,53 @@ pub async fn discover_endpoint<S: ServiceEndpointRegistry, M>(

let registration_result = state.meta_handle().register(payload.uri, headers).await;
Ok(registration_result
.map(|services| RegisterEndpointResponse { services })?
.map(|services| RegisterServiceEndpointResponse { services })?
.into())
}

#[derive(Debug, Deserialize)]
pub struct ListEndpointsRequest {}

#[derive(Debug, Serialize)]
pub struct ListEndpointsResponse {
endpoints: Vec<GetEndpointResponse>,
pub struct ListServicesResponse {
endpoints: Vec<GetServiceResponse>,
}

/// List discovered endpoints
pub async fn list_endpoints<S: ServiceEndpointRegistry, M>(
/// List services
pub async fn list_services<S: ServiceEndpointRegistry, M>(
State(state): State<Arc<RestEndpointState<S, M>>>,
Query(_): Query<ListEndpointsRequest>,
) -> Result<Json<ListEndpointsResponse>, MetaApiError> {
Ok(ListEndpointsResponse {
) -> Result<Json<ListServicesResponse>, MetaApiError> {
Ok(ListServicesResponse {
endpoints: state
.service_endpoint_registry()
.list_endpoints()
.iter()
.map(|(service_name, metadata)| GetEndpointResponse {
.map(|(service_name, metadata)| GetServiceResponse {
service_name: service_name.clone(),
metadata: metadata.clone(),
endpoint_metadata: metadata.clone(),
})
.collect(),
}
.into())
}

#[derive(Debug, Deserialize)]
pub struct GetEndpointRequest {}

#[derive(Debug, Serialize)]
pub struct GetEndpointResponse {
pub struct GetServiceResponse {
service_name: String,
metadata: EndpointMetadata,
endpoint_metadata: EndpointMetadata,
}

/// Get an endpoint
pub async fn get_endpoint<S: ServiceEndpointRegistry, M>(
/// Get a service
pub async fn get_service<S: ServiceEndpointRegistry, M>(
State(state): State<Arc<RestEndpointState<S, M>>>,
Path(service_name): Path<String>,
Query(_): Query<GetEndpointRequest>,
) -> Result<Json<GetEndpointResponse>, MetaApiError> {
let endpoint = state
) -> Result<Json<GetServiceResponse>, MetaApiError> {
match state
.service_endpoint_registry()
.resolve_endpoint(service_name.clone());
match endpoint {
Some(metadata) => Ok(GetEndpointResponse {
.resolve_endpoint(service_name.clone())
{
Some(endpoint_metadata) => Ok(GetServiceResponse {
service_name,
metadata,
endpoint_metadata,
}
.into()),
None => Err(MetaApiError::NotFound("service", service_name)),
None => Err(MetaApiError::ServiceNotFound(service_name)),
}
}
13 changes: 7 additions & 6 deletions src/service_metadata/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,17 @@ mod header_map {
use serde::Serializer;
use std::collections::HashMap;

#[allow(clippy::mutable_key_type)]
pub fn serialize<S: Serializer>(
headers: &HashMap<HeaderName, HeaderValue>,
ser: S,
) -> Result<S::Ok, S::Error> {
ser.collect_map(
headers
.iter()
.map(|(k, v)| (k.as_str(), v.to_str().unwrap())),
)
ser.collect_map(headers.iter().map(|(k, v)| {
(
k.as_str(),
v.to_str()
.expect("additional_headers map contains non-ASCII characters"),
)
}))
}
}

Expand Down

0 comments on commit 592a3ef

Please sign in to comment.