Skip to content

Commit

Permalink
add responses
Browse files Browse the repository at this point in the history
  • Loading branch information
kayhhh committed Dec 18, 2023
1 parent 2eab967 commit db3487a
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 62 deletions.
44 changes: 27 additions & 17 deletions dwn-server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ use axum::{
routing::post,
Json, Router,
};
use dwn::data::{Message, RecordIdGenerator};
use dwn::{
request::{Message, RecordIdGenerator, RequestBody},
response::{MessageResult, ResponseBody, Status},
};
use tracing::{error, info, span, warn};

pub struct StartOptions {
Expand Down Expand Up @@ -40,22 +43,29 @@ pub async fn start(StartOptions { port }: StartOptions) {
}
}

// https://identity.foundation/decentralized-web-node/spec/#request-level-status-coding
const DID_NOT_FOUND: (StatusCode, &str) = (StatusCode::NOT_FOUND, "DID not found");
const SERVER_ERROR: (StatusCode, &str) = (
StatusCode::INTERNAL_SERVER_ERROR,
"The request could not be processed correctly",
);

async fn post_handler(body: Json<dwn::data::RequestBody>) -> Response {
for message in body.0.messages.iter() {
if let Err(e) = process_message(message) {
warn!("{}", e);
return SERVER_ERROR.into_response();
}
}

StatusCode::OK.into_response()
async fn post_handler(body: Json<RequestBody>) -> Response {
let replies = body
.0
.messages
.iter()
.map(|message| match process_message(message) {
Ok(_) => StatusCode::OK,
Err(e) => {
warn!("{}", e);
StatusCode::BAD_REQUEST
}
})
.map(|code| MessageResult {
status: Status::new(code.as_u16(), None),
entries: None,
})
.collect::<Vec<_>>();

Json(ResponseBody {
status: Some(Status::new(StatusCode::OK.as_u16(), None)),
replies: Some(replies),
})
.into_response()
}

fn process_message(message: &Message) -> Result<(), Box<dyn std::error::Error>> {
Expand Down
95 changes: 52 additions & 43 deletions dwn-server/tests/messages.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use dwn::data::{DescriptorBuilder, Message, MessageBuilder, RequestBody};
use dwn::{
request::{DescriptorBuilder, Message, MessageBuilder, RequestBody},
response::ResponseBody,
};
use dwn_server::StartOptions;
use reqwest::StatusCode;
use reqwest::{Response, StatusCode};

fn spawn_server() -> u16 {
let port = port_check::free_local_port().expect("Failed to find free port");
Expand All @@ -15,21 +18,16 @@ fn spawn_server() -> u16 {
port
}

async fn send_post(data: dwn::data::RequestBody, port: u16) -> StatusCode {
async fn send_post(data: RequestBody, port: u16) -> Response {
let client = reqwest::Client::new();

let res = match client
client
.post(format!("http://localhost:{}", port))
.header("Content-Type", "application/json")
.body(serde_json::to_string(&data).expect("Failed to serialize data"))
.send()
.await
{
Ok(res) => res,
Err(e) => panic!("{}", e),
};

res.status()
.expect("Failed to send request")
}

fn empty_message() -> Message {
Expand All @@ -53,24 +51,47 @@ async fn recieve_post() {
messages: vec![empty_message()],
};

assert_eq!(send_post(body, port).await, StatusCode::OK);
let res = send_post(body, port).await;

assert_eq!(res.status(), StatusCode::OK);
}

async fn expect_status(body: RequestBody, port: u16, status: StatusCode) {
let res = send_post(body, port)
.await
.json::<ResponseBody>()
.await
.expect("Failed to parse response body");

for reply in res.replies.unwrap().iter() {
assert_eq!(reply.status.code, status);
}
}

#[tokio::test]
async fn requires_valid_record_id() {
let port = spawn_server();

let mut msg = empty_message();
msg.record_id = "invalid record id".to_string();
// Valid record ID
{
let body = RequestBody {
messages: vec![empty_message()],
};

let body = RequestBody {
messages: vec![msg],
};
expect_status(body, port, StatusCode::OK).await;
}

// Invalid record ID
{
let mut msg = empty_message();
msg.record_id = "invalid record id".to_string();

assert_eq!(
send_post(body, port).await,
StatusCode::INTERNAL_SERVER_ERROR
);
let body = RequestBody {
messages: vec![msg],
};

expect_status(body, port, StatusCode::BAD_REQUEST).await;
}
}

#[tokio::test]
Expand All @@ -82,30 +103,18 @@ async fn requires_data_descriptors() {
msg.descriptor.data_cid = Some("test data cid".to_string());
msg.descriptor.data_format = Some("test data format".to_string());

let mut without_cid = msg.clone();
without_cid.descriptor.data_cid = None;

let mut without_format = msg.clone();
without_format.descriptor.data_format = None;

let mut without_both = msg.clone();
without_both.descriptor.data_cid = None;

let body = RequestBody {
messages: vec![msg],
messages: vec![without_cid, without_format, without_both],
};

let mut without_cid = body.clone();
without_cid.messages[0].descriptor.data_cid = None;

let mut without_format = body.clone();
without_format.messages[0].descriptor.data_format = None;

let mut without_both = body.clone();
without_both.messages[0].descriptor.data_cid = None;
without_both.messages[0].descriptor.data_format = None;

assert_eq!(
send_post(without_cid, port).await,
StatusCode::INTERNAL_SERVER_ERROR
);
assert_eq!(
send_post(without_format, port).await,
StatusCode::INTERNAL_SERVER_ERROR
);
assert_eq!(
send_post(without_both, port).await,
StatusCode::INTERNAL_SERVER_ERROR
);
expect_status(body, port, StatusCode::BAD_REQUEST).await;
}
5 changes: 3 additions & 2 deletions dwn/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod data;
pub mod util;
pub mod request;
pub mod response;
mod util;
File renamed without changes.
32 changes: 32 additions & 0 deletions dwn/src/response.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use serde::{Deserialize, Serialize};

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ResponseBody {
#[serde(skip_serializing_if = "Option::is_none")]
pub status: Option<Status>,
#[serde(skip_serializing_if = "Option::is_none")]
pub replies: Option<Vec<MessageResult>>,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Status {
pub code: u16,
#[serde(skip_serializing_if = "Option::is_none")]
pub detail: Option<String>,
}

impl Status {
pub fn new(code: u16, detail: Option<String>) -> Self {
Self { code, detail }
}
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct MessageResult {
pub status: Status,
#[serde(skip_serializing_if = "Option::is_none")]
pub entries: Option<Vec<Entry>>,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Entry {}

0 comments on commit db3487a

Please sign in to comment.