1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#![doc(html_logo_url = "https://avatars2.githubusercontent.com/u/52050279?s=200&v=4")]
//! # HTTP Server wasmCloud Actor Interface
//!
//! This crate provides wasmCloud actors with an interface to the HTTP Server capability provider. Actors using this
//! interface must have the claim `wasmcloud:httpserver` in order to have permission to handle requests, and they
//! must have an active, configured binding to an HTTP Server capability provider.
//!
//! The HTTP Server provider is one-way, and only delivers messages to actors. Actors cannot make host calls
//! to this provider. To make outbound http requests, actors will need to use a `wasmcloud:httpclient` provider.
//!
//! # Example:
//! ```
//! use wasmcloud_actor_http_server as http;
//! use wasmcloud_actor_core as actor;
//! use wapc_guest::HandlerResult;
//! use http::{Request, Response, Handlers, Method};
//!
//! #[actor::init]
//! fn init() {
//!     http::Handlers::register_handle_request(req_handler);
//! }
//!
//! fn req_handler(req: http::Request) -> HandlerResult<http::Response> {
//!     let method = req.method();
//!     let segments = req.path_segments();
//!
//!     match (method, &*segments)  {
//!         (Method::Get, &["v0", "users", id]) => get_user(id),
//!         (Method::Put, &["v1", "users", id]) => update_user(id, &req.body),
//!         _ => Ok(http::Response::not_found())
//!     }
//! }
//!
//! fn get_user(id: &str) -> HandlerResult<http::Response> {
//!     Ok(http::Response::ok())
//! }
//! fn update_user(id: &str, body: &[u8]) -> HandlerResult<http::Response> {
//!     Ok(http::Response::ok())
//! }
//! ```

pub mod generated;
mod route;
use serde::Serialize;
use std::collections::HashMap;

pub use route::Method;

#[cfg(feature = "guest")]
pub use generated::Handlers;
pub use generated::{deserialize, serialize, Request, Response};

use std::str::FromStr;

impl Request {
    pub fn path_segments(&self) -> Vec<&str> {
        self.path.split('/').skip(1).collect::<Vec<_>>()
    }

    pub fn method(&self) -> Method {
        Method::from_str(&self.method).unwrap()
    }
}

impl Response {
    /// Creates a response with a given status code and serializes the given payload as JSON
    pub fn json<T>(payload: T, status_code: u32, status: &str) -> Response
    where
        T: Serialize,
    {
        Response {
            body: serde_json::to_string(&payload).unwrap().into_bytes(),
            header: HashMap::new(),
            status: status.to_string(),
            status_code,
        }
    }

    /// Handy shortcut for creating a 404/Not Found response
    pub fn not_found() -> Response {
        Response {
            status: "Not Found".to_string(),
            status_code: 404,
            ..Default::default()
        }
    }

    /// Useful shortcut for creating a 200/OK response
    pub fn ok() -> Response {
        Response {
            status: "OK".to_string(),
            status_code: 200,
            ..Default::default()
        }
    }

    /// Useful shortcut for creating a 500/Internal Server Error response
    pub fn internal_server_error(msg: &str) -> Response {
        Response {
            status: "Internal Server Error".to_string(),
            status_code: 500,
            body: msg.to_string().as_bytes().into(),
            ..Default::default()
        }
    }

    /// Shortcut for creating a 400/Bad Request response
    pub fn bad_request() -> Response {
        Response {
            status: "Bad Request".to_string(),
            status_code: 400,
            ..Default::default()
        }
    }
}

#[cfg(test)]
#[cfg(feature = "guest")]
mod test {
    extern crate wapc_guest;
    use crate::{Handlers, Request, Response};
    use wapc_guest::HandlerResult;
    #[test]
    fn it_works() {
        Handlers::register_handle_request(hr);
        assert!(true);
    }

    fn hr(_req: Request) -> HandlerResult<Response> {
        Ok(Response::ok())
    }
}