rustful_api/
lib.rs

1
2//! # RUSTful-API
3//!
4//! A library to make creating and starting a RESTful API server quick, easy, and secure
5
6/*
7/// # `rustful_api` namespace
8/// Has all the high level interactions to create and run a RESTful API server
9///
10/// ## Method
11/// An enum of allowed operations on endpoints
12///
13/// ## Response
14/// The response that the requester will receive (Headers, Content (Text or JSON), and parameters)
15///
16/// ## Request
17/// The incoming request with Headers, Content (Text or JSON), and parameters
18///
19/// ## Endpoint
20/// A combination of the operation method and a path string
21///
22/// ## Api
23/// A collections of endpoints that can be run to start the REST server
24 */
25use std;
26use std::collections::HashMap;
27use std::net::TcpListener;
28
29/// # Method
30/// An enum of allowed operations on endpoints
31/// - `GET`
32/// - `PUT`
33/// - `POST`
34/// - `DELETE`
35/// - `OPTIONS`
36#[derive(Hash, PartialEq)]
37pub enum Method {
38    GET,
39    PUT,
40    POST,
41    DELETE,
42    OPTIONS
43}
44pub struct Request;
45pub struct Response {
46    pub code: u16
47}
48#[derive(Hash)]
49pub struct Endpoint {
50    pub(crate) method: Method,
51    pub(crate) path: String,
52}
53/// # Api
54/// A collections of endpoints that can be run to start the REST server
55///
56/// ## Example
57/// ```
58/// use rustful_api::*;
59///
60/// let mut api = Api::new();
61/// fn handle_root_request(request: Request) -> Response {
62///     println!("Received request on path '/'!");
63///     Response {code: 204}
64/// }
65/// api.add_endpoint(Method::GET, String::from("/"), handle_root_request);
66/// // api.start(None, None);
67/// ```
68pub struct Api {
69    pub(crate) endpoints: HashMap<Endpoint, fn(Request) -> Response>
70}
71
72impl Api {
73    pub fn new() -> Api {
74        Api { endpoints : HashMap::new() }
75    }
76
77    pub fn add_endpoint(&mut self, method: Method, path: String, handler: fn(Request) -> Response) {
78        let endpoint = Endpoint { method, path };
79        self.endpoints.insert(endpoint, handler);
80    }
81
82    pub fn start(&mut self, bind_address: Option<String>, bind_port: Option<u32>) {
83        let hostname = bind_address.unwrap_or(String::from("127.0.0.1"));
84        let port = bind_port.unwrap_or(8080);
85        let tcp_listener = TcpListener::bind(String::from(format!("{}:{}", hostname, port))).unwrap();
86        for stream in tcp_listener.incoming() {
87            let in_stream = stream.unwrap();
88            println!("Connection established!");
89        }
90    }
91}
92
93impl PartialEq for Endpoint {
94    fn eq(&self, other: &Self) -> bool {
95        return self.method == other.method
96            && self.path == other.path;
97    }
98}
99impl Eq for Endpoint {}
100
101
102#[cfg(test)]
103mod tests {
104    use super::*;
105
106    fn api_test_handler(_request: Request) -> Response {
107        println!("Received request");
108        Response { code: 200 }
109    }
110
111    #[test]
112    fn test_adding_an_endpoint() {
113        let mut api = Api::new();
114        api.add_endpoint(Method::GET, String::from("/api/test"), api_test_handler);
115        let my_model = Endpoint { method: Method::GET, path: String::from("/api/test") };
116        assert!(api.endpoints.contains_key(&my_model));
117    }
118}