diff --git a/src/packet.rs b/src/packet.rs
index 103a54e50348fdb123f94bd04e1ebe020670b305..27adf694e7d05f243ac6971089308b8971166683 100644
--- a/src/packet.rs
+++ b/src/packet.rs
@@ -18,13 +18,172 @@ pub enum PacketType {
 }
 
 #[derive(Default, Debug, RustcEncodable, RustcDecodable)]
-pub struct PacketHeader {
+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;
@@ -84,14 +243,11 @@ impl PacketHeader {
 		assert_eq!(0xF8 & class_code, 0);
 		assert_eq!(0xE0 & detail_code, 0);
 
-		self.code = class_code << 5 | detail_code;
+		self.code = code_to_class(&(class_code << 5 | detail_code));
 	}
 
 	pub fn get_code(&self) -> String {
-		let class_code = (0xE0 & self.code) >> 5;
-		let detail_code = 0x1F & self.code;
-
-		return format!("{}.{:02}", class_code, detail_code);
+		class_to_str(&self.code)
 	}
 
 	#[inline]
@@ -152,7 +308,7 @@ pub struct Packet {
 impl Packet {
 	pub fn new() -> Packet {
 		Packet {
-			header: PacketHeader::default(),
+			header: PacketHeader::new(),
 			token: Vec::new(),
 			options: BTreeMap::new(),
 			payload: Vec::new(),
@@ -202,9 +358,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<PacketHeader> = bincode::decode(buf);
+		let header_result: bincode::DecodingResult<PacketHeaderRaw> = bincode::decode(buf);
 		match header_result {
-			Ok(header) => {
+			Ok(raw_header) => {
+				let header = PacketHeader::from_raw(&raw_header);
 				let token_length = header.get_token_length();
 				let options_start: usize = 4 + token_length as usize;
 
@@ -373,7 +530,7 @@ impl Packet {
 		}
 
 		let mut buf_length = 4 + self.payload.len() + self.token.len();
-		if self.header.get_code() != "0.00" && self.payload.len() != 0 {
+		if self.header.code != PacketClass::Empty && self.payload.len() != 0 {
 			buf_length += 1;
 		}
 		buf_length += options_bytes.len();
@@ -383,7 +540,7 @@ impl Packet {
 		}
 
 		let mut buf: Vec<u8> = Vec::with_capacity(buf_length);
-		let header_result: bincode::EncodingResult<()> = bincode::encode_into(&self.header, &mut buf, bincode::SizeLimit::Infinite);
+		let header_result: bincode::EncodingResult<()> = bincode::encode_into(&self.header.to_raw(), &mut buf, bincode::SizeLimit::Infinite);
 		match header_result {
 			Ok(_) => {
 				buf.reserve(self.token.len() + options_bytes.len());
@@ -395,7 +552,7 @@ impl Packet {
 					buf.set_len(buf_len + self.token.len() + options_bytes.len());
 				}
 
-				if self.header.get_code() != "0.00" && self.payload.len() != 0 {
+				if self.header.code != PacketClass::Empty && self.payload.len() != 0 {
 					buf.push(0xFF);
 					buf.reserve(self.payload.len());
 					unsafe {
@@ -446,7 +603,7 @@ pub fn auto_response(request_packet: &Packet) -> Option<Packet> {
 			_ => return None
 		};
 		packet.header.set_type(response_type);
-		packet.header.set_code("2.05");
+		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());
 
@@ -460,6 +617,22 @@ mod test {
 	use super::*;
 	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, 0x65, 0x73, 0x74, 0x43, 0x61, 0x3d, 0x31];
@@ -469,7 +642,7 @@ mod test {
 		assert_eq!(packet.header.get_version(), 1);
 		assert_eq!(packet.header.get_type(), PacketType::Confirmable);
 		assert_eq!(packet.header.get_token_length(), 4);
-		assert_eq!(packet.header.get_code(), "0.01");
+		assert_eq!(packet.header.code, PacketClass::Request(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);
@@ -499,7 +672,7 @@ mod test {
 		assert_eq!(packet.header.get_version(), 1);
 		assert_eq!(packet.header.get_type(), PacketType::Acknowledgement);
 		assert_eq!(packet.header.get_token_length(), 4);
-		assert_eq!(packet.header.get_code(), "2.05");
+		assert_eq!(packet.header.code, PacketClass::Response(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());
@@ -510,7 +683,7 @@ mod test {
 		let mut packet = Packet::new();
 		packet.header.set_version(1);
 		packet.header.set_type(PacketType::Confirmable);
-		packet.header.set_code("0.01");
+		packet.header.code = PacketClass::Request(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());
@@ -524,7 +697,7 @@ mod test {
 		let mut packet = Packet::new();
 		packet.header.set_version(1);
 		packet.header.set_type(PacketType::Acknowledgement);
-		packet.header.set_code("2.05");
+		packet.header.code = PacketClass::Response(Responses::Content);
 		packet.header.set_message_id(5117);
 		packet.set_token(vec!(0xD0, 0xE2, 0x4D, 0xAC));
 		packet.payload = "Hello".as_bytes().to_vec();