diff --git a/.gitignore b/.gitignore
index a9d37c560c6ab8d4afbf47eda643e8c42e857716..5057d9ef2736ef163008cf7b4baca67f1e866732 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
 target
 Cargo.lock
+*.rs.bk
diff --git a/README.md b/README.md
index 8c46e80ce04fdd7d8ca23656f33f289f77e8c936..8c6d91a3dbeedb58403bf4e4e2f15d78d6ec1116 100644
--- a/README.md
+++ b/README.md
@@ -33,10 +33,9 @@ extern crate coap;
 extern crate coap;
 
 use std::io;
-use coap::packet::*;
-use coap::{CoAPServer, CoAPClient};
+use coap::{CoAPResponse, CoAPRequest};
 
-fn request_handler(req: Packet, response: Option<Packet>) -> Option<Packet> {
+fn request_handler(req: CoAPRequest) -> Option<CoAPResponse> {
 	println!("Receive request: {:?}", req);
 	response
 }
@@ -59,15 +58,14 @@ fn main() {
 ```rust
 extern crate coap;
 
-use coap::packet::*;
-use coap::CoAPClient;
+use coap::{CoAPClient, CoAPResponse};
 
 fn main() {
 	let url = "coap://127.0.0.1:5683/Rust";
 	println!("Client request: {}", url);
 
-	let response: Packet = CoAPClient::request(url).unwrap();
-	println!("Server reply: {}", String::from_utf8(response.payload).unwrap());
+	let response: CoAPResponse = CoAPClient::request(url).unwrap();
+	println!("Server reply: {}", String::from_utf8(response.message.payload).unwrap());
 }
 ```
 
diff --git a/benches/client.rs b/benches/client.rs
index 7fa45f2ab7f9408a06576a0c5adbc7fc5158d215..6ba830ba2cebde2709ce78daf55411aaa3ef5819 100644
--- a/benches/client.rs
+++ b/benches/client.rs
@@ -13,11 +13,11 @@ fn bench_client_request(b: &mut Bencher) {
 	let request = "test";
 	let mut packet = Packet::new();
 	packet.header.set_version(1);
-	packet.header.set_type(PacketType::Confirmable);
+	packet.header.set_type(MessageType::Confirmable);
 	packet.header.set_code("0.01");
 	packet.header.set_message_id(1);
 	packet.set_token(vec!(0x51, 0x55, 0x77, 0xE8));
-	packet.add_option(OptionType::UriPath, request.to_string().into_bytes());
+	packet.add_option(CoAPOption::UriPath, request.to_string().into_bytes());
 
 	b.iter(|| {
 		let client = CoAPClient::new(addr).unwrap();
diff --git a/examples/client.rs b/examples/client.rs
index 865a56c37a4838d4bd8360b714caa5e16c3824cb..fd28755df58efad76898d5f85b07f6e11e79af83 100644
--- a/examples/client.rs
+++ b/examples/client.rs
@@ -1,34 +1,34 @@
 extern crate coap;
 
 use std::io::ErrorKind;
-use coap::packet::*;
-use coap::CoAPClient;
+use coap::{CoAPClient, CoAPRequest, IsMessage, MessageType, CoAPOption};
 
 fn main() {
-	let addr = "127.0.0.1:5683";
-	let request = "test";
+    let addr = "127.0.0.1:5683";
+    let endpoint = "test";
 
-	let client = CoAPClient::new(addr).unwrap();
-	let mut packet = Packet::new();
-	packet.header.set_version(1);
-	packet.header.set_type(PacketType::Confirmable);
-	packet.header.set_code("0.01");
-	packet.header.set_message_id(1);
-	packet.set_token(vec!(0x51, 0x55, 0x77, 0xE8));
-	packet.add_option(OptionType::UriPath, request.to_string().into_bytes());
-	client.send(&packet).unwrap();
-	println!("Client request: coap://{}/{}", addr, request);
+    let client = CoAPClient::new(addr).unwrap();
+    let mut request = CoAPRequest::new();
+    request.set_version(1);
+    request.set_type(MessageType::Confirmable);
+    request.set_code("0.01");
+    request.set_message_id(1);
+    request.set_token(vec![0x51, 0x55, 0x77, 0xE8]);
+    request.add_option(CoAPOption::UriPath, endpoint.to_string().into_bytes());
+    client.send(&request).unwrap();
+    println!("Client request: coap://{}/{}", addr, endpoint);
 
-	match client.receive() {
-		Ok(response) => {
-			println!("Server reply: {}", String::from_utf8(response.payload).unwrap());
-		},
-		Err(e) => {
-			match e.kind() {
-			    ErrorKind::WouldBlock => println!("Request timeout"),   // Unix
-			    ErrorKind::TimedOut => println!("Request timeout"),     // Windows
-			    _ => println!("Request error: {:?}", e),
-			}
-		}
-	}
+    match client.receive() {
+        Ok(response) => {
+            println!("Server reply: {}",
+                     String::from_utf8(response.message.payload).unwrap());
+        }
+        Err(e) => {
+            match e.kind() {
+                ErrorKind::WouldBlock => println!("Request timeout"),   // Unix
+                ErrorKind::TimedOut => println!("Request timeout"),     // Windows
+                _ => println!("Request error: {:?}", e),
+            }
+        }
+    }
 }
diff --git a/examples/client_and_server.rs b/examples/client_and_server.rs
index 1d5fb6e0baf80e296e609ff41750810e8670ec93..0e474bdfca83e7e5fa7e4e832e7241752e496f82 100644
--- a/examples/client_and_server.rs
+++ b/examples/client_and_server.rs
@@ -1,27 +1,28 @@
 extern crate coap;
 
-use coap::packet::*;
-use coap::{CoAPServer, CoAPClient};
+use coap::{CoAPServer, CoAPClient, CoAPRequest, CoAPResponse, CoAPOption};
+use coap::IsMessage;
 
-fn request_handler(req: Packet, response: Option<Packet>) -> Option<Packet> {
-	let uri_path = req.get_option(OptionType::UriPath).unwrap();
+fn request_handler(request: CoAPRequest) -> Option<CoAPResponse> {
+    let uri_path = request.get_option(CoAPOption::UriPath).unwrap();
 
-	return match response {
-		Some(mut packet) => {
-			packet.set_payload(uri_path.front().unwrap().clone());
-			Some(packet)
-		},
-		_ => None
+    return match request.response {
+        Some(mut response) => {
+            response.set_payload(uri_path.front().unwrap().clone());
+            Some(response)
+        }
+        _ => None,
     };
 }
 
 fn main() {
-	let mut server = CoAPServer::new("127.0.0.1:5683").unwrap();
-	server.handle(request_handler).unwrap();
+    let mut server = CoAPServer::new("127.0.0.1:5683").unwrap();
+    server.handle(request_handler).unwrap();
 
-	let url = "coap://127.0.0.1:5683/Rust";
-	println!("Client request: {}", url);
+    let url = "coap://127.0.0.1:5683/Rust";
+    println!("Client request: {}", url);
 
-	let response: Packet = CoAPClient::request(url).unwrap();
-	println!("Server reply: {}", String::from_utf8(response.payload).unwrap());
+    let response: CoAPResponse = CoAPClient::request(url).unwrap();
+    println!("Server reply: {}",
+             String::from_utf8(response.message.payload).unwrap());
 }
diff --git a/examples/server.rs b/examples/server.rs
index 887e4ae3b282a3d2dee641751d1304bc59c64054..28d13029087bba6fb4fc2dd631c2019cd219a1fc 100644
--- a/examples/server.rs
+++ b/examples/server.rs
@@ -1,29 +1,28 @@
 extern crate coap;
 
 use std::io;
-use coap::packet::*;
-use coap::CoAPServer;
+use coap::{CoAPServer, CoAPResponse, CoAPRequest, IsMessage};
 
-fn request_handler(_: Packet, response: Option<Packet>) -> Option<Packet> {
-	return match response {
-		Some(mut packet) => {
-			packet.set_payload(b"OK".to_vec());
-			Some(packet)
+fn request_handler(request: CoAPRequest) -> Option<CoAPResponse> {
+	return match request.response {
+		Some(mut message) => {
+			message.set_payload(b"OK".to_vec());
+			Some(message)
 		},
 		_ => None
 	};
 }
 
 fn main() {
-	let addr = "127.0.0.1:5683";
+    let addr = "127.0.0.1:5683";
 
-	let mut server = CoAPServer::new(addr).unwrap();
-	server.handle(request_handler).unwrap();
+    let mut server = CoAPServer::new(addr).unwrap();
+    server.handle(request_handler).unwrap();
 
-	println!("Server up on {}", addr);
-	println!("Press any key to stop...");
+    println!("Server up on {}", addr);
+    println!("Press any key to stop...");
 
-	io::stdin().read_line(&mut String::new()).unwrap();
+    io::stdin().read_line(&mut String::new()).unwrap();
 
-	println!("Server shutdown");
+    println!("Server shutdown");
 }
diff --git a/src/client.rs b/src/client.rs
index e5c5c89c14acb7d29a0c4a38a17de88f338351ba..dcac775fa48d93f49c7c68fafdfdce86b114a259 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -4,7 +4,11 @@ use std::time::Duration;
 use url::{UrlParser, SchemeType};
 use num;
 use rand::{thread_rng, random, Rng};
-use packet::{Packet, PacketType, OptionType};
+use message::packet::{Packet, CoAPOption};
+use message::header::MessageType;
+use message::response::CoAPResponse;
+use message::request::CoAPRequest;
+use message::IsMessage;
 
 const DEFAULT_RECEIVE_TIMEOUT: u64 = 5;  // 5s
 
@@ -46,19 +50,19 @@ impl CoAPClient {
     }
 
     /// Execute a request with the coap url and a specific timeout. Default timeout is 5s.
-    pub fn request_with_timeout(url: &str, timeout: Option<Duration>) -> Result<Packet> {
+    pub fn request_with_timeout(url: &str, timeout: Option<Duration>) -> Result<CoAPResponse> {
         let mut url_parser = UrlParser::new();
         url_parser.scheme_type_mapper(Self::coap_scheme_type_mapper);
 
         match url_parser.parse(url) {
             Ok(url_params) => {
-                let mut packet = Packet::new();
-                packet.header.set_version(1);
-                packet.header.set_type(PacketType::Confirmable);
-                packet.header.set_code("0.01");
+                let mut packet = CoAPRequest::new();
+                packet.set_version(1);
+                packet.set_type(MessageType::Confirmable);
+                packet.set_code("0.01");
 
                 let message_id = thread_rng().gen_range(0, num::pow(2u32, 16)) as u16;
-                packet.header.set_message_id(message_id);
+                packet.set_message_id(message_id);
 
                 let mut token: Vec<u8> = vec![1, 1, 1, 1];
                 for x in token.iter_mut() {
@@ -74,7 +78,7 @@ impl CoAPClient {
 
                 if let Some(path) = url_params.path() {
                     for p in path.iter() {
-                        packet.add_option(OptionType::UriPath, p.clone().into_bytes().to_vec());
+                        packet.add_option(CoAPOption::UriPath, p.clone().into_bytes().to_vec());
                     }
                 };
 
@@ -84,7 +88,7 @@ impl CoAPClient {
                 try!(client.set_receive_timeout(timeout));
                 match client.receive() {
                     Ok(receive_packet) => {
-                        if receive_packet.header.get_message_id() == message_id &&
+                        if receive_packet.get_message_id() == message_id &&
                            *receive_packet.get_token() == token {
                             return Ok(receive_packet);
                         } else {
@@ -99,13 +103,13 @@ impl CoAPClient {
     }
 
     /// Execute a request with the coap url.
-    pub fn request(url: &str) -> Result<Packet> {
+    pub fn request(url: &str) -> Result<CoAPResponse> {
         Self::request_with_timeout(url, Some(Duration::new(DEFAULT_RECEIVE_TIMEOUT, 0)))
     }
 
     /// Execute a request.
-    pub fn send(&self, packet: &Packet) -> Result<()> {
-        match packet.to_bytes() {
+    pub fn send(&self, request: &CoAPRequest) -> Result<()> {
+        match request.message.to_bytes() {
             Ok(bytes) => {
                 let size = try!(self.socket.send_to(&bytes[..], self.peer_addr));
                 if size == bytes.len() {
@@ -119,12 +123,12 @@ impl CoAPClient {
     }
 
     /// Receive a response.
-    pub fn receive(&self) -> Result<Packet> {
+    pub fn receive(&self) -> Result<CoAPResponse> {
         let mut buf = [0; 1500];
 
         let (nread, _src) = try!(self.socket.recv_from(&mut buf));
         match Packet::from_bytes(&buf[..nread]) {
-            Ok(packet) => Ok(packet),
+            Ok(packet) => Ok(CoAPResponse { message: packet }),
             Err(_) => Err(Error::new(ErrorKind::InvalidInput, "packet error")),
         }
     }
@@ -148,7 +152,8 @@ mod test {
     use super::*;
     use std::time::Duration;
     use std::io::ErrorKind;
-    use packet::Packet;
+    use message::request::CoAPRequest;
+    use message::response::CoAPResponse;
     use server::CoAPServer;
 
     #[test]
@@ -158,7 +163,7 @@ mod test {
         assert!(CoAPClient::request("127.0.0.1").is_err());
     }
 
-    fn request_handler(_: Packet, _: Option<Packet>) -> Option<Packet> {
+    fn request_handler(_: CoAPRequest) -> Option<CoAPResponse> {
         None
     }
 
diff --git a/src/lib.rs b/src/lib.rs
index 5344b44803a051f8499b54c33680adbcee80c19c..1c1c7322e9a6b877ddf088a996463894c9632f41 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -27,11 +27,10 @@
 //! extern crate coap;
 
 //! use std::io;
-//! use coap::packet::*;
-//! use coap::{CoAPServer, CoAPClient};
+//! use coap::{CoAPServer, CoAPClient, CoAPRequest, CoAPResponse};
 
-//! fn request_handler(req: Packet, resp: Option<Packet>) -> Option<Packet> {
-//! 	println!("Receive request: {:?}", req);
+//! fn request_handler(request: CoAPRequest) -> Option<CoAPResponse> {
+//! 	println!("Receive request: {:?}", request);
 //!     None
 //! }
 
@@ -54,15 +53,15 @@
 //! ```no_run
 //! extern crate coap;
 //!
-//! use coap::packet::*;
+//! use coap::message::response::CoAPResponse;
 //! use coap::CoAPClient;
 //!
 //! fn main() {
 //! 	let url = "coap://127.0.0.1:5683/Rust";
 //! 	println!("Client request: {}", url);
 //!
-//! 	let response: Packet = CoAPClient::request(url).unwrap();
-//! 	println!("Server reply: {}", String::from_utf8(response.payload).unwrap());
+//! 	let response: CoAPResponse = CoAPClient::request(url).unwrap();
+//! 	println!("Server reply: {}", String::from_utf8(response.message.payload).unwrap());
 //! }
 //! ```
 
@@ -79,9 +78,14 @@ extern crate quickcheck;
 #[macro_use]
 extern crate log;
 
-pub use server::CoAPServer;
 pub use client::CoAPClient;
+pub use message::header::MessageType;
+pub use message::IsMessage;
+pub use message::packet::CoAPOption;
+pub use message::request::CoAPRequest;
+pub use message::response::CoAPResponse;
+pub use server::CoAPServer;
 
-pub mod packet;
+pub mod message;
 pub mod client;
 pub mod server;
diff --git a/src/message/header.rs b/src/message/header.rs
new file mode 100644
index 0000000000000000000000000000000000000000..57ad3b2353875cd92e17167b3f57bdac2546efab
--- /dev/null
+++ b/src/message/header.rs
@@ -0,0 +1,272 @@
+#[derive(Default, Debug, RustcEncodable, RustcDecodable)]
+pub struct HeaderRaw {
+    ver_type_tkl: u8,
+    code: u8,
+    message_id: u16,
+}
+
+#[derive(Debug)]
+pub struct Header {
+    ver_type_tkl: u8,
+    pub code: MessageClass,
+    message_id: u16,
+}
+
+#[derive(Debug, PartialEq)]
+pub enum MessageClass {
+    Empty,
+    RequestType(Requests),
+    ResponseType(Responses),
+    Reserved,
+}
+
+#[derive(Debug, PartialEq)]
+pub enum Requests {
+    Get,
+    Post,
+    Put,
+    Delete,
+}
+
+#[derive(Debug, PartialEq)]
+pub enum Responses {
+    // 200 Codes
+    Created,
+    Deleted,
+    Valid,
+    Changed,
+    Content,
+
+    // 400 Codes
+    BadRequest,
+    Unauthorized,
+    BadOption,
+    Forbidden,
+    NotFound,
+    MethodNotAllowed,
+    NotAcceptable,
+    PreconditionFailed,
+    RequestEntityTooLarge,
+    UnsupportedContentFormat,
+
+    // 500 Codes
+    InternalServerError,
+    NotImplemented,
+    BadGateway,
+    ServiceUnavailable,
+    GatewayTimeout,
+    ProxyingNotSupported,
+}
+
+#[derive(PartialEq, Eq, Debug)]
+pub enum MessageType {
+    Confirmable,
+    NonConfirmable,
+    Acknowledgement,
+    Reset,
+    Invalid,
+}
+
+impl Header {
+    pub fn new() -> Header {
+        return Header::from_raw(&HeaderRaw::default());
+    }
+
+    pub fn from_raw(raw: &HeaderRaw) -> Header {
+        return Header {
+            ver_type_tkl: raw.ver_type_tkl,
+            code: code_to_class(&raw.code),
+            message_id: raw.message_id,
+        };
+    }
+
+    pub fn to_raw(&self) -> HeaderRaw {
+        return HeaderRaw {
+            ver_type_tkl: self.ver_type_tkl,
+            code: class_to_code(&self.code),
+            message_id: self.message_id,
+        };
+    }
+
+    #[inline]
+    pub fn set_version(&mut self, v: u8) {
+        let type_tkl = 0x3F & self.ver_type_tkl;
+        self.ver_type_tkl = v << 6 | type_tkl;
+    }
+
+    #[inline]
+    pub fn get_version(&self) -> u8 {
+        return self.ver_type_tkl >> 6;
+    }
+
+    #[inline]
+    pub fn set_type(&mut self, t: MessageType) {
+        let tn = match t {
+            MessageType::Confirmable => 0,
+            MessageType::NonConfirmable => 1,
+            MessageType::Acknowledgement => 2,
+            MessageType::Reset => 3,
+            _ => unreachable!(),
+        };
+
+        let ver_tkl = 0xCF & self.ver_type_tkl;
+        self.ver_type_tkl = tn << 4 | ver_tkl;
+    }
+
+    #[inline]
+    pub fn get_type(&self) -> MessageType {
+        let tn = (0x30 & self.ver_type_tkl) >> 4;
+        match tn {
+            0 => MessageType::Confirmable,
+            1 => MessageType::NonConfirmable,
+            2 => MessageType::Acknowledgement,
+            3 => MessageType::Reset,
+            _ => MessageType::Invalid,
+        }
+    }
+
+    #[inline]
+    pub fn set_token_length(&mut self, tkl: u8) {
+        assert_eq!(0xF0 & tkl, 0);
+
+        let ver_type = 0xF0 & self.ver_type_tkl;
+        self.ver_type_tkl = tkl | ver_type;
+    }
+
+    #[inline]
+    pub fn get_token_length(&self) -> u8 {
+        return 0x0F & self.ver_type_tkl;
+    }
+
+    pub fn set_code(&mut self, code: &str) {
+        let code_vec: Vec<&str> = code.split('.').collect();
+        assert_eq!(code_vec.len(), 2);
+
+        let class_code = code_vec[0].parse::<u8>().unwrap();
+        let detail_code = code_vec[1].parse::<u8>().unwrap();
+        assert_eq!(0xF8 & class_code, 0);
+        assert_eq!(0xE0 & detail_code, 0);
+
+        self.code = code_to_class(&(class_code << 5 | detail_code));
+    }
+
+    pub fn get_code(&self) -> String {
+        class_to_str(&self.code)
+    }
+
+    #[inline]
+    pub fn set_message_id(&mut self, message_id: u16) {
+        self.message_id = message_id;
+    }
+
+    #[inline]
+    pub fn get_message_id(&self) -> u16 {
+        return self.message_id;
+    }
+}
+
+pub fn class_to_code(class: &MessageClass) -> u8 {
+    return match *class {
+        MessageClass::Empty => 0x00,
+
+        MessageClass::RequestType(Requests::Get) => 0x01,
+        MessageClass::RequestType(Requests::Post) => 0x02,
+        MessageClass::RequestType(Requests::Put) => 0x03,
+        MessageClass::RequestType(Requests::Delete) => 0x04,
+
+        MessageClass::ResponseType(Responses::Created) => 0x41,
+        MessageClass::ResponseType(Responses::Deleted) => 0x42,
+        MessageClass::ResponseType(Responses::Valid) => 0x43,
+        MessageClass::ResponseType(Responses::Changed) => 0x44,
+        MessageClass::ResponseType(Responses::Content) => 0x45,
+
+        MessageClass::ResponseType(Responses::BadRequest) => 0x80,
+        MessageClass::ResponseType(Responses::Unauthorized) => 0x81,
+        MessageClass::ResponseType(Responses::BadOption) => 0x82,
+        MessageClass::ResponseType(Responses::Forbidden) => 0x83,
+        MessageClass::ResponseType(Responses::NotFound) => 0x84,
+        MessageClass::ResponseType(Responses::MethodNotAllowed) => 0x85,
+        MessageClass::ResponseType(Responses::NotAcceptable) => 0x86,
+        MessageClass::ResponseType(Responses::PreconditionFailed) => 0x8C,
+        MessageClass::ResponseType(Responses::RequestEntityTooLarge) => 0x8D,
+        MessageClass::ResponseType(Responses::UnsupportedContentFormat) => 0x8F,
+
+        MessageClass::ResponseType(Responses::InternalServerError) => 0x90,
+        MessageClass::ResponseType(Responses::NotImplemented) => 0x91,
+        MessageClass::ResponseType(Responses::BadGateway) => 0x92,
+        MessageClass::ResponseType(Responses::ServiceUnavailable) => 0x93,
+        MessageClass::ResponseType(Responses::GatewayTimeout) => 0x94,
+        MessageClass::ResponseType(Responses::ProxyingNotSupported) => 0x95,
+
+        _ => 0xFF,
+    } as u8;
+}
+
+pub fn code_to_class(code: &u8) -> MessageClass {
+    match *code {
+        0x00 => MessageClass::Empty,
+
+        0x01 => MessageClass::RequestType(Requests::Get),
+        0x02 => MessageClass::RequestType(Requests::Post),
+        0x03 => MessageClass::RequestType(Requests::Put),
+        0x04 => MessageClass::RequestType(Requests::Delete),
+
+        0x41 => MessageClass::ResponseType(Responses::Created),
+        0x42 => MessageClass::ResponseType(Responses::Deleted),
+        0x43 => MessageClass::ResponseType(Responses::Valid),
+        0x44 => MessageClass::ResponseType(Responses::Changed),
+        0x45 => MessageClass::ResponseType(Responses::Content),
+
+        0x80 => MessageClass::ResponseType(Responses::BadRequest),
+        0x81 => MessageClass::ResponseType(Responses::Unauthorized),
+        0x82 => MessageClass::ResponseType(Responses::BadOption),
+        0x83 => MessageClass::ResponseType(Responses::Forbidden),
+        0x84 => MessageClass::ResponseType(Responses::NotFound),
+        0x85 => MessageClass::ResponseType(Responses::MethodNotAllowed),
+        0x86 => MessageClass::ResponseType(Responses::NotAcceptable),
+        0x8C => MessageClass::ResponseType(Responses::PreconditionFailed),
+        0x8D => MessageClass::ResponseType(Responses::RequestEntityTooLarge),
+        0x8F => MessageClass::ResponseType(Responses::UnsupportedContentFormat),
+
+        0x90 => MessageClass::ResponseType(Responses::InternalServerError),
+        0x91 => MessageClass::ResponseType(Responses::NotImplemented),
+        0x92 => MessageClass::ResponseType(Responses::BadGateway),
+        0x93 => MessageClass::ResponseType(Responses::ServiceUnavailable),
+        0x94 => MessageClass::ResponseType(Responses::GatewayTimeout),
+        0x95 => MessageClass::ResponseType(Responses::ProxyingNotSupported),
+
+        _ => MessageClass::Reserved,
+    }
+}
+
+pub fn code_to_str(code: &u8) -> String {
+    let class_code = (0xE0 & code) >> 5;
+    let detail_code = 0x1F & code;
+
+    return format!("{}.{:02}", class_code, detail_code);
+}
+
+pub fn class_to_str(class: &MessageClass) -> String {
+    return code_to_str(&class_to_code(class));
+}
+
+#[cfg(test)]
+mod test {
+    use message::header::*;
+
+    #[test]
+    fn test_header_codes() {
+        for code in 0..255 {
+            let class = code_to_class(&code);
+            let code_str = code_to_str(&code);
+            let class_str = class_to_str(&class);
+
+            // Reserved class could technically be many codes
+            //   so only check valid items
+            if class != MessageClass::Reserved {
+                assert_eq!(class_to_code(&class), code);
+                assert_eq!(code_str, class_str);
+            }
+        }
+    }
+}
diff --git a/src/message/mod.rs b/src/message/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..6f1b93da80229362aa47de217b6f42a6aaca1ded
--- /dev/null
+++ b/src/message/mod.rs
@@ -0,0 +1,60 @@
+pub mod header;
+pub mod request;
+pub mod response;
+pub mod packet;
+
+use message::packet::Packet;
+use message::header::Header;
+
+use std::collections::LinkedList;
+
+pub trait IsMessage {
+    fn get_message(&self) -> &Packet;
+    fn get_mut_message(&mut self) -> &mut Packet;
+    fn get_header(&self) -> &Header;
+    fn get_mut_header(&mut self) -> &mut Header;
+
+    fn set_token(&mut self, token: Vec<u8>) {
+        self.get_mut_message().set_token(token);
+    }
+    fn get_token(&self) -> &Vec<u8> {
+        return self.get_message().get_token();
+    }
+    fn set_option(&mut self, tp: packet::CoAPOption, value: LinkedList<Vec<u8>>) {
+        self.get_mut_message().set_option(tp, value);
+    }
+    fn set_payload(&mut self, payload: Vec<u8>) {
+        self.get_mut_message().set_payload(payload);
+    }
+    fn add_option(&mut self, tp: packet::CoAPOption, value: Vec<u8>) {
+        self.get_mut_message().add_option(tp, value);
+    }
+    fn get_option(&self, tp: packet::CoAPOption) -> Option<LinkedList<Vec<u8>>> {
+        return self.get_message().get_option(tp);
+    }
+
+    fn get_message_id(&self) -> u16 {
+        return self.get_message().header.get_message_id();
+    }
+    fn set_message_id(&mut self, message_id: u16) {
+        self.get_mut_message().header.set_message_id(message_id);
+    }
+    fn set_version(&mut self, v: u8) {
+        self.get_mut_message().header.set_version(v);
+    }
+    fn get_version(&self) -> u8 {
+        return self.get_message().header.get_version();
+    }
+    fn set_type(&mut self, t: header::MessageType) {
+        self.get_mut_message().header.set_type(t);
+    }
+    fn get_type(&self) -> header::MessageType {
+        return self.get_message().header.get_type();
+    }
+    fn get_code(&self) -> String {
+        return self.get_message().header.get_code();
+    }
+    fn set_code(&mut self, code: &str) {
+        self.get_mut_message().header.set_code(code);
+    }
+}
diff --git a/src/packet.rs b/src/message/packet.rs
similarity index 55%
rename from src/packet.rs
rename to src/message/packet.rs
index 58d2a4a06bcd20783199992884b9649ea9c2e64c..a2e401012d53b8d38a8b5256ba250050bb439a2d 100644
--- a/src/packet.rs
+++ b/src/message/packet.rs
@@ -2,280 +2,16 @@ use bincode;
 use std::collections::BTreeMap;
 use std::collections::LinkedList;
 
-macro_rules! u8_to_unsigned_be {
-	($src:ident, $start:expr, $end:expr, $t:ty) => ({
-		(0 .. $end - $start + 1).rev().fold(0, |acc, i| acc | $src[$start+i] as $t << i * 8)
-	})
-}
-
-#[derive(PartialEq, Eq, Debug)]
-pub enum PacketType {
-    Confirmable,
-    NonConfirmable,
-    Acknowledgement,
-    Reset,
-    Invalid,
-}
-
-#[derive(Default, Debug, RustcEncodable, RustcDecodable)]
-pub struct PacketHeaderRaw {
-    ver_type_tkl: u8,
-    code: u8,
-    message_id: u16,
-}
-
-#[derive(Debug)]
-pub struct PacketHeader {
-    ver_type_tkl: u8,
-    pub code: PacketClass,
-    message_id: u16,
-}
-
-#[derive(Debug, PartialEq)]
-pub enum PacketClass {
-    Empty,
-    Request(Requests),
-    Response(Responses),
-    Reserved,
-}
-
-#[derive(Debug, PartialEq)]
-pub enum Requests {
-    Get,
-    Post,
-    Put,
-    Delete,
-}
-
-#[derive(Debug, PartialEq)]
-pub enum Responses {
-    // 200 Codes
-    Created,
-    Deleted,
-    Valid,
-    Changed,
-    Content,
-
-    // 400 Codes
-    BadRequest,
-    Unauthorized,
-    BadOption,
-    Forbidden,
-    NotFound,
-    MethodNotAllowed,
-    NotAcceptable,
-    PreconditionFailed,
-    RequestEntityTooLarge,
-    UnsupportedContentFormat,
-
-    // 500 Codes
-    InternalServerError,
-    NotImplemented,
-    BadGateway,
-    ServiceUnavailable,
-    GatewayTimeout,
-    ProxyingNotSupported,
-}
-
-pub fn class_to_code(class: &PacketClass) -> u8 {
-    return match *class {
-        PacketClass::Empty => 0x00,
-
-        PacketClass::Request(Requests::Get) => 0x01,
-        PacketClass::Request(Requests::Post) => 0x02,
-        PacketClass::Request(Requests::Put) => 0x03,
-        PacketClass::Request(Requests::Delete) => 0x04,
-
-        PacketClass::Response(Responses::Created) => 0x41,
-        PacketClass::Response(Responses::Deleted) => 0x42,
-        PacketClass::Response(Responses::Valid) => 0x43,
-        PacketClass::Response(Responses::Changed) => 0x44,
-        PacketClass::Response(Responses::Content) => 0x45,
-
-        PacketClass::Response(Responses::BadRequest) => 0x80,
-        PacketClass::Response(Responses::Unauthorized) => 0x81,
-        PacketClass::Response(Responses::BadOption) => 0x82,
-        PacketClass::Response(Responses::Forbidden) => 0x83,
-        PacketClass::Response(Responses::NotFound) => 0x84,
-        PacketClass::Response(Responses::MethodNotAllowed) => 0x85,
-        PacketClass::Response(Responses::NotAcceptable) => 0x86,
-        PacketClass::Response(Responses::PreconditionFailed) => 0x8C,
-        PacketClass::Response(Responses::RequestEntityTooLarge) => 0x8D,
-        PacketClass::Response(Responses::UnsupportedContentFormat) => 0x8F,
-
-        PacketClass::Response(Responses::InternalServerError) => 0x90,
-        PacketClass::Response(Responses::NotImplemented) => 0x91,
-        PacketClass::Response(Responses::BadGateway) => 0x92,
-        PacketClass::Response(Responses::ServiceUnavailable) => 0x93,
-        PacketClass::Response(Responses::GatewayTimeout) => 0x94,
-        PacketClass::Response(Responses::ProxyingNotSupported) => 0x95,
-
-        _ => 0xFF,
-    } as u8;
-}
-
-pub fn code_to_class(code: &u8) -> PacketClass {
-    match *code {
-        0x00 => PacketClass::Empty,
-
-        0x01 => PacketClass::Request(Requests::Get),
-        0x02 => PacketClass::Request(Requests::Post),
-        0x03 => PacketClass::Request(Requests::Put),
-        0x04 => PacketClass::Request(Requests::Delete),
-
-        0x41 => PacketClass::Response(Responses::Created),
-        0x42 => PacketClass::Response(Responses::Deleted),
-        0x43 => PacketClass::Response(Responses::Valid),
-        0x44 => PacketClass::Response(Responses::Changed),
-        0x45 => PacketClass::Response(Responses::Content),
-
-        0x80 => PacketClass::Response(Responses::BadRequest),
-        0x81 => PacketClass::Response(Responses::Unauthorized),
-        0x82 => PacketClass::Response(Responses::BadOption),
-        0x83 => PacketClass::Response(Responses::Forbidden),
-        0x84 => PacketClass::Response(Responses::NotFound),
-        0x85 => PacketClass::Response(Responses::MethodNotAllowed),
-        0x86 => PacketClass::Response(Responses::NotAcceptable),
-        0x8C => PacketClass::Response(Responses::PreconditionFailed),
-        0x8D => PacketClass::Response(Responses::RequestEntityTooLarge),
-        0x8F => PacketClass::Response(Responses::UnsupportedContentFormat),
-
-        0x90 => PacketClass::Response(Responses::InternalServerError),
-        0x91 => PacketClass::Response(Responses::NotImplemented),
-        0x92 => PacketClass::Response(Responses::BadGateway),
-        0x93 => PacketClass::Response(Responses::ServiceUnavailable),
-        0x94 => PacketClass::Response(Responses::GatewayTimeout),
-        0x95 => PacketClass::Response(Responses::ProxyingNotSupported),
-
-        _ => PacketClass::Reserved,
-    }
-}
-
-pub fn code_to_str(code: &u8) -> String {
-    let class_code = (0xE0 & code) >> 5;
-    let detail_code = 0x1F & code;
-
-    return format!("{}.{:02}", class_code, detail_code);
-}
-
-pub fn class_to_str(class: &PacketClass) -> String {
-    return code_to_str(&class_to_code(class));
-}
-
-impl PacketHeader {
-    pub fn new() -> PacketHeader {
-        return PacketHeader::from_raw(&PacketHeaderRaw::default());
-    }
-
-    pub fn from_raw(raw: &PacketHeaderRaw) -> PacketHeader {
-        return PacketHeader {
-            ver_type_tkl: raw.ver_type_tkl,
-            code: code_to_class(&raw.code),
-            message_id: raw.message_id,
-        };
-    }
-
-    pub fn to_raw(&self) -> PacketHeaderRaw {
-        return PacketHeaderRaw {
-            ver_type_tkl: self.ver_type_tkl,
-            code: class_to_code(&self.code),
-            message_id: self.message_id,
-        };
-    }
-
-    #[inline]
-    pub fn set_version(&mut self, v: u8) {
-        let type_tkl = 0x3F & self.ver_type_tkl;
-        self.ver_type_tkl = v << 6 | type_tkl;
-    }
-
-    #[inline]
-    pub fn get_version(&self) -> u8 {
-        return self.ver_type_tkl >> 6;
-    }
-
-    #[inline]
-    pub fn set_type(&mut self, t: PacketType) {
-        let tn = match t {
-            PacketType::Confirmable => 0,
-            PacketType::NonConfirmable => 1,
-            PacketType::Acknowledgement => 2,
-            PacketType::Reset => 3,
-            _ => unreachable!(),
-        };
-
-        let ver_tkl = 0xCF & self.ver_type_tkl;
-        self.ver_type_tkl = tn << 4 | ver_tkl;
-    }
-
-    #[inline]
-    pub fn get_type(&self) -> PacketType {
-        let tn = (0x30 & self.ver_type_tkl) >> 4;
-        match tn {
-            0 => PacketType::Confirmable,
-            1 => PacketType::NonConfirmable,
-            2 => PacketType::Acknowledgement,
-            3 => PacketType::Reset,
-            _ => PacketType::Invalid,
-        }
-    }
-
-    #[inline]
-    fn set_token_length(&mut self, tkl: u8) {
-        assert_eq!(0xF0 & tkl, 0);
-
-        let ver_type = 0xF0 & self.ver_type_tkl;
-        self.ver_type_tkl = tkl | ver_type;
-    }
-
-    #[inline]
-    fn get_token_length(&self) -> u8 {
-        return 0x0F & self.ver_type_tkl;
-    }
+use message::header;
 
-    pub fn set_code(&mut self, code: &str) {
-        let code_vec: Vec<&str> = code.split('.').collect();
-        assert_eq!(code_vec.len(), 2);
-
-        let class_code = code_vec[0].parse::<u8>().unwrap();
-        let detail_code = code_vec[1].parse::<u8>().unwrap();
-        assert_eq!(0xF8 & class_code, 0);
-        assert_eq!(0xE0 & detail_code, 0);
-
-        self.code = code_to_class(&(class_code << 5 | detail_code));
-    }
-
-    pub fn get_code(&self) -> String {
-        class_to_str(&self.code)
-    }
-
-    #[inline]
-    pub fn set_message_id(&mut self, message_id: u16) {
-        self.message_id = message_id;
-    }
-
-    #[inline]
-    pub fn get_message_id(&self) -> u16 {
-        return self.message_id;
-    }
-}
-
-#[derive(Debug)]
-pub enum ParseError {
-    InvalidHeader,
-    InvalidTokenLength,
-    InvalidOptionDelta,
-    InvalidOptionLength,
-}
-
-#[derive(Debug)]
-pub enum PackageError {
-    InvalidHeader,
-    InvalidPacketLength,
+macro_rules! u8_to_unsigned_be {
+    ($src:ident, $start:expr, $end:expr, $t:ty) => ({
+        (0 .. $end - $start + 1).rev().fold(0, |acc, i| acc | $src[$start+i] as $t << i * 8)
+    })
 }
 
 #[derive(PartialEq, Eq, Debug)]
-pub enum OptionType {
+pub enum CoAPOption {
     IfMatch,
     UriHost,
     ETag,
@@ -296,9 +32,23 @@ pub enum OptionType {
     Size1,
 }
 
+#[derive(Debug)]
+pub enum PackageError {
+    InvalidHeader,
+    InvalidPacketLength,
+}
+
+#[derive(Debug)]
+pub enum ParseError {
+    InvalidHeader,
+    InvalidTokenLength,
+    InvalidOptionDelta,
+    InvalidOptionLength,
+}
+
 #[derive(Debug)]
 pub struct Packet {
-    pub header: PacketHeader,
+    pub header: header::Header,
     token: Vec<u8>,
     options: BTreeMap<usize, LinkedList<Vec<u8>>>,
     pub payload: Vec<u8>,
@@ -307,7 +57,7 @@ pub struct Packet {
 impl Packet {
     pub fn new() -> Packet {
         Packet {
-            header: PacketHeader::new(),
+            header: header::Header::new(),
             token: Vec::new(),
             options: BTreeMap::new(),
             payload: Vec::new(),
@@ -323,7 +73,7 @@ impl Packet {
         return &self.token;
     }
 
-    pub fn set_option(&mut self, tp: OptionType, value: LinkedList<Vec<u8>>) {
+    pub fn set_option(&mut self, tp: CoAPOption, value: LinkedList<Vec<u8>>) {
         let num = Self::get_option_number(tp);
         self.options.insert(num, value);
     }
@@ -332,7 +82,7 @@ impl Packet {
         self.payload = payload;
     }
 
-    pub fn add_option(&mut self, tp: OptionType, value: Vec<u8>) {
+    pub fn add_option(&mut self, tp: CoAPOption, value: Vec<u8>) {
         let num = Self::get_option_number(tp);
         match self.options.get_mut(&num) {
             Some(list) => {
@@ -347,7 +97,7 @@ impl Packet {
         self.options.insert(num, list);
     }
 
-    pub fn get_option(&self, tp: OptionType) -> Option<LinkedList<Vec<u8>>> {
+    pub fn get_option(&self, tp: CoAPOption) -> Option<LinkedList<Vec<u8>>> {
         let num = Self::get_option_number(tp);
         match self.options.get(&num) {
             Some(options) => Some(options.clone()),
@@ -357,10 +107,10 @@ impl Packet {
 
     /// Decodes a byte slice and construct the equivalent Packet.
     pub fn from_bytes(buf: &[u8]) -> Result<Packet, ParseError> {
-        let header_result: bincode::DecodingResult<PacketHeaderRaw> = bincode::decode(buf);
+        let header_result: bincode::DecodingResult<header::HeaderRaw> = bincode::decode(buf);
         match header_result {
             Ok(raw_header) => {
-                let header = PacketHeader::from_raw(&raw_header);
+                let header = header::Header::from_raw(&raw_header);
                 let token_length = header.get_token_length();
                 let options_start: usize = 4 + token_length as usize;
 
@@ -535,7 +285,7 @@ impl Packet {
         }
 
         let mut buf_length = 4 + self.payload.len() + self.token.len();
-        if self.header.code != PacketClass::Empty && self.payload.len() != 0 {
+        if self.header.code != header::MessageClass::Empty && self.payload.len() != 0 {
             buf_length += 1;
         }
         buf_length += options_bytes.len();
@@ -564,7 +314,7 @@ impl Packet {
                     buf.set_len(buf_len + self.token.len() + options_bytes.len());
                 }
 
-                if self.header.code != PacketClass::Empty && self.payload.len() != 0 {
+                if self.header.code != header::MessageClass::Empty && self.payload.len() != 0 {
                     buf.push(0xFF);
                     buf.reserve(self.payload.len());
                     unsafe {
@@ -582,71 +332,36 @@ impl Packet {
         }
     }
 
-    fn get_option_number(tp: OptionType) -> usize {
+    fn get_option_number(tp: CoAPOption) -> usize {
         match tp {
-            OptionType::IfMatch => 1,
-            OptionType::UriHost => 3,
-            OptionType::ETag => 4,
-            OptionType::IfNoneMatch => 5,
-            OptionType::Observe => 6,
-            OptionType::UriPort => 7,
-            OptionType::LocationPath => 8,
-            OptionType::UriPath => 11,
-            OptionType::ContentFormat => 12,
-            OptionType::MaxAge => 14,
-            OptionType::UriQuery => 15,
-            OptionType::Accept => 17,
-            OptionType::LocationQuery => 20,
-            OptionType::Block2 => 23,
-            OptionType::Block1 => 27,
-            OptionType::ProxyUri => 35,
-            OptionType::ProxyScheme => 39,
-            OptionType::Size1 => 60,
+            CoAPOption::IfMatch => 1,
+            CoAPOption::UriHost => 3,
+            CoAPOption::ETag => 4,
+            CoAPOption::IfNoneMatch => 5,
+            CoAPOption::Observe => 6,
+            CoAPOption::UriPort => 7,
+            CoAPOption::LocationPath => 8,
+            CoAPOption::UriPath => 11,
+            CoAPOption::ContentFormat => 12,
+            CoAPOption::MaxAge => 14,
+            CoAPOption::UriQuery => 15,
+            CoAPOption::Accept => 17,
+            CoAPOption::LocationQuery => 20,
+            CoAPOption::Block2 => 23,
+            CoAPOption::Block1 => 27,
+            CoAPOption::ProxyUri => 35,
+            CoAPOption::ProxyScheme => 39,
+            CoAPOption::Size1 => 60,
         }
     }
 }
 
-/// Convert a request to a response
-pub fn auto_response(request_packet: &Packet) -> Option<Packet> {
-    let mut packet = Packet::new();
-
-    packet.header.set_version(1);
-    let response_type = match request_packet.header.get_type() {
-        PacketType::Confirmable => PacketType::Acknowledgement,
-        PacketType::NonConfirmable => PacketType::NonConfirmable,
-        _ => return None,
-    };
-    packet.header.set_type(response_type);
-    packet.header.code = PacketClass::Response(Responses::Content);
-    packet.header.set_message_id(request_packet.header.get_message_id());
-    packet.set_token(request_packet.get_token().clone());
-
-    packet.payload = request_packet.payload.clone();
-
-    Some(packet)
-}
-
 #[cfg(test)]
 mod test {
     use super::*;
+    use super::super::header;
     use std::collections::LinkedList;
 
-    #[test]
-    fn test_header_codes() {
-        for code in 0..255 {
-            let class = code_to_class(&code);
-            let code_str = code_to_str(&code);
-            let class_str = class_to_str(&class);
-
-            // Reserved class could technically be many codes
-            //   so only check valid items
-            if class != PacketClass::Reserved {
-                assert_eq!(class_to_code(&class), code);
-                assert_eq!(code_str, class_str);
-            }
-        }
-    }
-
     #[test]
     fn test_decode_packet_with_options() {
         let buf = [0x44, 0x01, 0x84, 0x9e, 0x51, 0x55, 0x77, 0xe8, 0xb2, 0x48, 0x69, 0x04, 0x54,
@@ -655,14 +370,15 @@ mod test {
         assert!(packet.is_ok());
         let packet = packet.unwrap();
         assert_eq!(packet.header.get_version(), 1);
-        assert_eq!(packet.header.get_type(), PacketType::Confirmable);
+        assert_eq!(packet.header.get_type(), header::MessageType::Confirmable);
         assert_eq!(packet.header.get_token_length(), 4);
-        assert_eq!(packet.header.code, PacketClass::Request(Requests::Get));
+        assert_eq!(packet.header.code,
+                   header::MessageClass::RequestType(header::Requests::Get));
         assert_eq!(packet.header.get_message_id(), 33950);
         assert_eq!(*packet.get_token(), vec![0x51, 0x55, 0x77, 0xE8]);
         assert_eq!(packet.options.len(), 2);
 
-        let uri_path = packet.get_option(OptionType::UriPath);
+        let uri_path = packet.get_option(CoAPOption::UriPath);
         assert!(uri_path.is_some());
         let uri_path = uri_path.unwrap();
         let mut expected_uri_path = LinkedList::new();
@@ -670,7 +386,7 @@ mod test {
         expected_uri_path.push_back("Test".as_bytes().to_vec());
         assert_eq!(uri_path, expected_uri_path);
 
-        let uri_query = packet.get_option(OptionType::UriQuery);
+        let uri_query = packet.get_option(CoAPOption::UriQuery);
         assert!(uri_query.is_some());
         let uri_query = uri_query.unwrap();
         let mut expected_uri_query = LinkedList::new();
@@ -686,10 +402,11 @@ mod test {
         assert!(packet.is_ok());
         let packet = packet.unwrap();
         assert_eq!(packet.header.get_version(), 1);
-        assert_eq!(packet.header.get_type(), PacketType::Acknowledgement);
+        assert_eq!(packet.header.get_type(),
+                   header::MessageType::Acknowledgement);
         assert_eq!(packet.header.get_token_length(), 4);
         assert_eq!(packet.header.code,
-                   PacketClass::Response(Responses::Content));
+                   header::MessageClass::ResponseType(header::Responses::Content));
         assert_eq!(packet.header.get_message_id(), 5117);
         assert_eq!(*packet.get_token(), vec![0xD0, 0xE2, 0x4D, 0xAC]);
         assert_eq!(packet.payload, "Hello".as_bytes().to_vec());
@@ -699,13 +416,13 @@ mod test {
     fn test_encode_packet_with_options() {
         let mut packet = Packet::new();
         packet.header.set_version(1);
-        packet.header.set_type(PacketType::Confirmable);
-        packet.header.code = PacketClass::Request(Requests::Get);
+        packet.header.set_type(header::MessageType::Confirmable);
+        packet.header.code = header::MessageClass::RequestType(header::Requests::Get);
         packet.header.set_message_id(33950);
         packet.set_token(vec![0x51, 0x55, 0x77, 0xE8]);
-        packet.add_option(OptionType::UriPath, b"Hi".to_vec());
-        packet.add_option(OptionType::UriPath, b"Test".to_vec());
-        packet.add_option(OptionType::UriQuery, b"a=1".to_vec());
+        packet.add_option(CoAPOption::UriPath, b"Hi".to_vec());
+        packet.add_option(CoAPOption::UriPath, b"Test".to_vec());
+        packet.add_option(CoAPOption::UriQuery, b"a=1".to_vec());
         assert_eq!(packet.to_bytes().unwrap(),
                    vec![0x44, 0x01, 0x84, 0x9e, 0x51, 0x55, 0x77, 0xe8, 0xb2, 0x48, 0x69, 0x04,
                         0x54, 0x65, 0x73, 0x74, 0x43, 0x61, 0x3d, 0x31]);
@@ -715,8 +432,8 @@ mod test {
     fn test_encode_packet_with_payload() {
         let mut packet = Packet::new();
         packet.header.set_version(1);
-        packet.header.set_type(PacketType::Acknowledgement);
-        packet.header.code = PacketClass::Response(Responses::Content);
+        packet.header.set_type(header::MessageType::Acknowledgement);
+        packet.header.code = header::MessageClass::ResponseType(header::Responses::Content);
         packet.header.set_message_id(5117);
         packet.set_token(vec![0xD0, 0xE2, 0x4D, 0xAC]);
         packet.payload = "Hello".as_bytes().to_vec();
diff --git a/src/message/request.rs b/src/message/request.rs
new file mode 100644
index 0000000000000000000000000000000000000000..620bae9a5b04dbbf42dd45f6f158a6803b40a5dd
--- /dev/null
+++ b/src/message/request.rs
@@ -0,0 +1,87 @@
+use message::IsMessage;
+use message::response::CoAPResponse;
+use message::packet::Packet;
+use message::header::Header;
+use std::net::SocketAddr;
+
+#[derive(Debug)]
+pub struct CoAPRequest {
+    pub message: Packet,
+    pub response: Option<CoAPResponse>,
+    pub source: Option<SocketAddr>,
+}
+
+impl CoAPRequest {
+    pub fn new() -> CoAPRequest {
+        CoAPRequest {
+            response: None,
+            message: Packet::new(),
+            source: None,
+        }
+    }
+
+    pub fn from_packet(packet: Packet, source: &SocketAddr) -> CoAPRequest {
+        CoAPRequest {
+            response: CoAPResponse::new(&packet),
+            message: packet,
+            source: Some(source.clone()),
+        }
+    }
+}
+
+impl IsMessage for CoAPRequest {
+    fn get_message(&self) -> &Packet {
+        &self.message
+    }
+    fn get_mut_message(&mut self) -> &mut Packet {
+        &mut self.message
+    }
+    fn get_header(&self) -> &Header {
+        &self.message.header
+    }
+    fn get_mut_header(&mut self) -> &mut Header {
+        &mut self.message.header
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use message::packet::{Packet, CoAPOption};
+    use message::header::MessageType;
+    use message::IsMessage;
+    use std::net::SocketAddr;
+    use std::str::FromStr;
+
+    #[test]
+    fn test_request_create() {
+
+        let mut packet = Packet::new();
+        let mut request1 = CoAPRequest::new();
+
+        packet.set_token(vec![0x17, 0x38]);
+        request1.set_token(vec![0x17, 0x38]);
+
+        packet.add_option(CoAPOption::UriPath, b"test-interface".to_vec());
+        request1.add_option(CoAPOption::UriPath, b"test-interface".to_vec());
+
+        packet.header.set_message_id(42);
+        request1.set_message_id(42);
+
+        packet.header.set_version(2);
+        request1.set_version(2);
+
+        packet.header.set_type(MessageType::Confirmable);
+        request1.set_type(MessageType::Confirmable);
+
+        packet.header.set_code("0.04");
+        request1.set_code("0.04");
+
+        let request2 = CoAPRequest::from_packet(packet,
+                                                &SocketAddr::from_str("127.0.0.1:1234").unwrap());
+
+        assert_eq!(request1.message.to_bytes().unwrap(),
+                   request2.message.to_bytes().unwrap());
+
+    }
+}
diff --git a/src/message/response.rs b/src/message/response.rs
new file mode 100644
index 0000000000000000000000000000000000000000..e5351d6280843804ee946d9163b5770bf9bb3911
--- /dev/null
+++ b/src/message/response.rs
@@ -0,0 +1,72 @@
+use message::IsMessage;
+use message::packet::Packet;
+use message::header::{Header, MessageType, MessageClass, Responses};
+
+#[derive(Debug)]
+pub struct CoAPResponse {
+    pub message: Packet,
+}
+
+impl CoAPResponse {
+    pub fn new(request: &Packet) -> Option<CoAPResponse> {
+        let mut packet = Packet::new();
+
+        packet.header.set_version(1);
+        let response_type = match request.header.get_type() {
+            MessageType::Confirmable => MessageType::Acknowledgement,
+            MessageType::NonConfirmable => MessageType::NonConfirmable,
+            _ => return None,
+        };
+        packet.header.set_type(response_type);
+        packet.header.code = MessageClass::ResponseType(Responses::Content);
+        packet.header.set_message_id(request.header.get_message_id());
+        packet.set_token(request.get_token().clone());
+
+        packet.payload = request.payload.clone();
+
+        Some(CoAPResponse { message: packet })
+    }
+}
+
+impl IsMessage for CoAPResponse {
+    fn get_message(&self) -> &Packet {
+        &self.message
+    }
+    fn get_mut_message(&mut self) -> &mut Packet {
+        &mut self.message
+    }
+    fn get_header(&self) -> &Header {
+        &self.message.header
+    }
+    fn get_mut_header(&mut self) -> &mut Header {
+        &mut self.message.header
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use message::packet::Packet;
+    use message::IsMessage;
+    use message::header::MessageType;
+
+    #[test]
+    fn test_new_response_valid() {
+        for mtyp in vec![MessageType::Confirmable, MessageType::NonConfirmable] {
+            let mut packet = Packet::new();
+            packet.header.set_type(mtyp);
+            let opt_resp = CoAPResponse::new(&packet);
+            assert!(opt_resp.is_some());
+
+            let response = opt_resp.unwrap();
+            assert_eq!(packet.payload, response.message.payload);
+        }
+    }
+
+    #[test]
+    fn test_new_response_invalid() {
+        let mut packet = Packet::new();
+        packet.header.set_type(MessageType::Acknowledgement);
+        assert!(CoAPResponse::new(&packet).is_none());
+    }
+}
diff --git a/src/server.rs b/src/server.rs
index 03c23c3941f0addf03c6dcc90c91d965d6f218f0..37b0392f0110edfc930dd9a1e76b0db72a1f18d3 100644
--- a/src/server.rs
+++ b/src/server.rs
@@ -5,12 +5,14 @@ use std::net::{ToSocketAddrs, SocketAddr};
 use std::sync::mpsc;
 use mio::{EventLoop, PollOpt, EventSet, Handler, Sender, Token};
 use mio::udp::UdpSocket;
-use packet::{Packet, auto_response};
+use message::packet::Packet;
+use message::request::CoAPRequest;
+use message::response::CoAPResponse;
 use threadpool::ThreadPool;
 
 const DEFAULT_WORKER_NUM: usize = 4;
-pub type TxQueue = mpsc::Sender<CoAPResponse>;
-pub type RxQueue = mpsc::Receiver<CoAPResponse>;
+type TxQueue = mpsc::Sender<QueuedResponse>;
+type RxQueue = mpsc::Receiver<QueuedResponse>;
 
 #[derive(Debug)]
 pub enum CoAPServerError {
@@ -20,21 +22,21 @@ pub enum CoAPServerError {
 }
 
 #[derive(Debug)]
-pub struct CoAPResponse {
+struct QueuedResponse {
     pub address: SocketAddr,
-    pub response: Packet,
+    pub response: CoAPResponse,
 }
 
 pub trait CoAPHandler: Sync + Send + Copy {
-    fn handle(&self, Packet, Option<Packet>) -> Option<Packet>;
+    fn handle(&self, CoAPRequest) -> Option<CoAPResponse>;
 }
 
 impl<F> CoAPHandler for F
-    where F: Fn(Packet, Option<Packet>) -> Option<Packet>,
+    where F: Fn(CoAPRequest) -> Option<CoAPResponse>,
           F: Sync + Send + Copy
 {
-    fn handle(&self, request: Packet, response: Option<Packet>) -> Option<Packet> {
-        return self(request, response);
+    fn handle(&self, request: CoAPRequest) -> Option<CoAPResponse> {
+        return self(request);
     }
 }
 
@@ -77,17 +79,17 @@ impl<H: CoAPHandler + 'static> Handler for UdpHandler<H> {
             Ok(Some((nread, src))) => {
                 debug!("Handling request from {}", src);
                 let response_q = self.tx_sender.clone();
+
                 self.thread_pool.execute(move || {
                     match Packet::from_bytes(&buf[..nread]) {
                         Ok(packet) => {
-                            // Pre-generate a response
-                            let auto_resp = auto_response(&packet);
                             // Dispatch user handler, if there is a response packet
                             //   send the reply via the TX thread
-                            match coap_handler.handle(packet, auto_resp) {
+                            let rqst = CoAPRequest::from_packet(packet, &src);
+                            match coap_handler.handle(rqst) {
                                 Some(response) => {
                                     debug!("Response: {:?}", response);
-                                    response_q.send(CoAPResponse {
+                                    response_q.send(QueuedResponse {
                                             address: src,
                                             response: response,
                                         })
@@ -224,7 +226,7 @@ fn transmit_handler(tx_recv: RxQueue, tx_only: UdpSocket) {
     loop {
         match tx_recv.recv() {
             Ok(q_res) => {
-                match q_res.response.to_bytes() {
+                match q_res.response.message.to_bytes() {
                     Ok(bytes) => {
                         let _ = tx_only.send_to(&bytes[..], &q_res.address);
                     }
@@ -252,18 +254,22 @@ impl Drop for CoAPServer {
 
 #[cfg(test)]
 mod test {
-    use super::*;
-    use packet::{Packet, PacketType, OptionType};
     use client::CoAPClient;
+    use message::header;
+    use message::IsMessage;
+    use message::packet::CoAPOption;
+    use message::request::CoAPRequest;
+    use message::response::CoAPResponse;
+    use super::*;
 
-    fn request_handler(req: Packet, response: Option<Packet>) -> Option<Packet> {
-        let uri_path_list = req.get_option(OptionType::UriPath).unwrap();
+    fn request_handler(req: CoAPRequest) -> Option<CoAPResponse> {
+        let uri_path_list = req.get_option(CoAPOption::UriPath).unwrap();
         assert!(uri_path_list.len() == 1);
 
-        match response {
-            Some(mut packet) => {
-                packet.set_payload(uri_path_list.front().unwrap().clone());
-                Some(packet)
+        match req.response {
+            Some(mut response) => {
+                response.set_payload(uri_path_list.front().unwrap().clone());
+                Some(response)
             }
             _ => None,
         }
@@ -275,17 +281,17 @@ mod test {
         server.handle(request_handler).unwrap();
 
         let client = CoAPClient::new("127.0.0.1:5683").unwrap();
-        let mut packet = Packet::new();
-        packet.header.set_version(1);
-        packet.header.set_type(PacketType::Confirmable);
-        packet.header.set_code("0.01");
-        packet.header.set_message_id(1);
-        packet.set_token(vec![0x51, 0x55, 0x77, 0xE8]);
-        packet.add_option(OptionType::UriPath, b"test-echo".to_vec());
-        client.send(&packet).unwrap();
+        let mut request = CoAPRequest::new();
+        request.set_version(1);
+        request.set_type(header::MessageType::Confirmable);
+        request.set_code("0.01");
+        request.set_message_id(1);
+        request.set_token(vec![0x51, 0x55, 0x77, 0xE8]);
+        request.add_option(CoAPOption::UriPath, b"test-echo".to_vec());
+        client.send(&request).unwrap();
 
         let recv_packet = client.receive().unwrap();
-        assert_eq!(recv_packet.payload, b"test-echo".to_vec());
+        assert_eq!(recv_packet.message.payload, b"test-echo".to_vec());
     }
 
     #[test]
@@ -294,15 +300,15 @@ mod test {
         server.handle(request_handler).unwrap();
 
         let client = CoAPClient::new("127.0.0.1:5683").unwrap();
-        let mut packet = Packet::new();
-        packet.header.set_version(1);
-        packet.header.set_type(PacketType::Confirmable);
-        packet.header.set_code("0.01");
-        packet.header.set_message_id(1);
-        packet.add_option(OptionType::UriPath, b"test-echo".to_vec());
+        let mut packet = CoAPRequest::new();
+        packet.set_version(1);
+        packet.set_type(header::MessageType::Confirmable);
+        packet.set_code("0.01");
+        packet.set_message_id(1);
+        packet.add_option(CoAPOption::UriPath, b"test-echo".to_vec());
         client.send(&packet).unwrap();
 
         let recv_packet = client.receive().unwrap();
-        assert_eq!(recv_packet.payload, b"test-echo".to_vec());
+        assert_eq!(recv_packet.message.payload, b"test-echo".to_vec());
     }
 }