     case connect = "CONNECT"
 }
 
+/// A type that represents an HTTP Body.
+///
+/// A `Body` is used by `Request` to create an `URLRequest`.
+///
+/// Adopted by `Data` and `String`.
+/// - seealso: `FormEncodedBody`, `JSONEncodedBody`.
 public protocol Body {
+    
+    /// Returns HTTP Header parameters required for `self`, if any.
+    ///
+    /// This is usally a "Content-Type" header like "application/json" for a
+    /// JSON encoded Body.
+    ///
+    /// Defaults to `nil`.
     var header: Parameters? { get }
+    
+    /// The body data that should be sent in an HTTP request.
     var requestData: Data { get }
 }
 

    }
}

public struct JSONEncodedBody: Body {
    public let requestData: Data
    
    public init(jsonObject: Any) throws {
        requestData = try JSONSerialization.data(withJSONObject: jsonObject, options: .prettyPrinted)
    }
    
    public var header: Parameters? {
        return [ "Content-Type" : "application/json" ]
    }
}

public protocol URLRequestEncodable: CustomDebugStringConvertible {
    var urlRequest: URLRequest { get }
}

extension URLRequestEncodable {
    public var debugDescription: String {
        return cURLRepresentation
    }
}

public struct Request: URLRequestEncodable {
    public var method: HTTPMethod
    public var url: URL
    public var header: Parameters?
    public var body: Body?
    
    public init(_ method: HTTPMethod, _ path: String?=nil, query: Parameters?=nil, header: Parameters?=nil, body: Body?=nil) {
        self.init(method, url: URL(path: path, query: query), header: header, body: body)
    }
    
    public init(_ method: HTTPMethod, url: URL, header: Parameters?=nil, body: Body?=nil) {
        self.method = method
        self.header = header

    }
}

/// A `Body` that represents a form encoded HTTP request body.
public struct FormEncodedBody: Body {
    
    /// The parameters dictionary to be encoded.
    public var parameters: Parameters
    
    /// Initialize with a parameters dictionary.
    /// 
    /// The parameters do not have to be percent encoded.
    public init(parameters: Parameters) {
        self.parameters = parameters
    }
    
    /// Returns "Content-Type": "application/x-www-form-urlencoded".
    public var header: Parameters? {
        return [ "Content-Type": "application/x-www-form-urlencoded" ]
    }
    
    /// Returns the encapsulated parameters dictionary as form encoded `Data`.
    public var requestData: Data {
        return parameters.map { key, value in
            return "\(encode(key))=\(encode(value))"
        }.joined(separator: "&").data(using: .utf8)!
    }
    
    /// add percent encoding to a string suitable for a form encoded request.
    func encode(_ string: String) -> String {
        guard let encoded = string.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) else {
            fatalError("failed to encode param string: \(string)")
