diff --git a/jsonapi-client.gemspec b/jsonapi-client.gemspec
index cd5a90b..95753c8 100644
--- a/jsonapi-client.gemspec
+++ b/jsonapi-client.gemspec
@@ -13,7 +13,8 @@ Gem::Specification.new do |spec|
   spec.files         = Dir['README.md', 'lib/**/*']
   spec.require_path  = 'lib'
 
-  spec.add_development_dependency 'jsonapi-parser', '0.1.1.beta2'
+  spec.add_dependency 'jsonapi-parser', '0.1.1.beta3'
+  spec.add_dependency 'jsonapi-renderer', '0.1.1.beta3'
   spec.add_development_dependency 'rake', '>=0.9'
   spec.add_development_dependency 'rspec', '~>3.4'
 end
diff --git a/lib/jsonapi/client.rb b/lib/jsonapi/client.rb
index dc47a5d..efe0156 100644
--- a/lib/jsonapi/client.rb
+++ b/lib/jsonapi/client.rb
@@ -1,7 +1,28 @@
 require 'jsonapi/parser'
 
 require 'jsonapi/client/document'
-require 'jsonapi/client/resource'
-require 'jsonapi/client/relationship'
-require 'jsonapi/client/link'
-require 'jsonapi/client/error'
+require 'jsonapi/client/request'
+require 'jsonapi/client/response'
+
+module JSONAPI
+  class Client
+    def initialize(base_url: nil, headers: {})
+      @base_url = base_url
+      @headers = {
+        :'Content-Type' => 'application/vnd.api+json',
+        :Accept => 'application/vnd.api+json'
+      }.merge!(headers)
+    end
+
+    def [](endpoint)
+      request(@base_url, endpoint)
+    end
+
+    def request(base_url, endpoint)
+      req = Request.new(base_url, endpoint)
+      req.headers(@headers) if @headers.any?
+
+      req
+    end
+  end
+end
diff --git a/lib/jsonapi/client/document.rb b/lib/jsonapi/client/document.rb
index 4ca1375..f859e2d 100644
--- a/lib/jsonapi/client/document.rb
+++ b/lib/jsonapi/client/document.rb
@@ -1,5 +1,10 @@
+require 'jsonapi/client/resource'
+require 'jsonapi/client/relationship'
+require 'jsonapi/client/link'
+require 'jsonapi/client/error'
+
 module JSONAPI
-  module Client
+  class Client
     class Document
       attr_reader :data, :included, :errors, :links, :meta
 
diff --git a/lib/jsonapi/client/error.rb b/lib/jsonapi/client/error.rb
index c7015fb..a5b5667 100644
--- a/lib/jsonapi/client/error.rb
+++ b/lib/jsonapi/client/error.rb
@@ -1,5 +1,5 @@
 module JSONAPI
-  module Client
+  class Client
     class Error
       attr_reader :id, :links, :status, :code, :title, :detail, :source, :meta
 
diff --git a/lib/jsonapi/client/link.rb b/lib/jsonapi/client/link.rb
index ea4bf4a..db623d9 100644
--- a/lib/jsonapi/client/link.rb
+++ b/lib/jsonapi/client/link.rb
@@ -1,5 +1,5 @@
 module JSONAPI
-  module Client
+  class Client
     class Link
       attr_reader :href, :meta
 
diff --git a/lib/jsonapi/client/relationship.rb b/lib/jsonapi/client/relationship.rb
index 9977148..d28117e 100644
--- a/lib/jsonapi/client/relationship.rb
+++ b/lib/jsonapi/client/relationship.rb
@@ -1,5 +1,5 @@
 module JSONAPI
-  module Client
+  class Client
     class Relationship
       attr_reader :data, :links, :meta
 
diff --git a/lib/jsonapi/client/request.rb b/lib/jsonapi/client/request.rb
new file mode 100644
index 0000000..95b89d6
--- /dev/null
+++ b/lib/jsonapi/client/request.rb
@@ -0,0 +1,164 @@
+require 'net/http'
+require 'uri'
+
+require 'jsonapi/include_directive'
+
+module JSONAPI
+  class Client
+    class Request
+      def initialize(base_url, endpoint = nil)
+        @base_url = base_url
+        @endpoint = endpoint
+        @params = {}
+        @headers = {}
+      end
+
+      def call
+        uri = URI(@base_url)
+        response =
+          Net::HTTP.start(uri.host, use_ssl: uri.scheme == 'https') do |http|
+            http.request request
+          end
+
+        Response.new(response)
+      end
+
+      def list
+        @method = :get
+        @uri = uri
+        self
+      end
+
+      def list!
+        list.call
+      end
+
+      def find(id)
+        @method = :get
+        @uri = uri(id)
+        self
+      end
+
+      def find!(id)
+        find(id).call
+      end
+
+      def create(hash)
+        hash[:type] ||= @endpoint
+        @method = :post
+        @uri = uri
+        @data = hash
+        self
+      end
+
+      def create!(hash)
+        create(hash).call
+      end
+
+      def update(id, hash)
+        hash[:type] ||= @endpoint
+        @method = :patch
+        @uri = uri(id)
+        @data = hash
+        self
+      end
+
+      def update!(id, hash)
+        update(id, hash).call
+      end
+
+      def delete(id)
+        @method = :delete
+        @uri = uri(id)
+        self
+      end
+
+      def delete!(id)
+        delete(id).call
+      end
+
+      def include(hash)
+        include = JSONAPI::IncludeDirective.new(hash).to_string
+        @params[:include] = include
+        self
+      end
+
+      def fields(hash)
+        hash = { @endpoint => hash } if hash.is_a?(Array)
+        hash.each do |k, v|
+          @params["fields[#{k}]".to_sym] = v.join(',')
+        end
+        self
+      end
+
+      def params(hash)
+        @params.merge!(hash)
+        self
+      end
+
+      def headers(hash)
+        @headers.merge!(hash)
+        self
+      end
+
+      def to_hash
+        {
+          method: @method,
+          uri: full_uri,
+          base_uri: @uri,
+          data: @data,
+          params: @params,
+          headers: @headers
+        }
+      end
+      alias to_h to_hash
+
+      private
+
+      def request
+        uri = URI(full_uri)
+        request =
+          case @method
+          when :get
+            Net::HTTP::Get.new(uri)
+          when :post
+            Net::HTTP::Post.new(uri).tap do |req|
+              req.body = @data
+            end
+          when :patch
+            Net::HTTP::Patch.new(uri).tap do |req|
+              req.body = @data
+            end
+          when :delete
+            Net::HTTP::Delete.new(uri)
+          else
+            raise "Unknown request method: #{@method}"
+          end
+        @headers.each_with_object(request) do |(k, v), r|
+          r[k] = v
+        end
+      end
+
+      def query
+        @params.map { |k, v| "#{k}=#{v}" }.join('&')
+      end
+
+      def uri(id = nil)
+        uri = @base_url
+        uri += "/#{@endpoint}" unless @endpoint.nil?
+        uri += "/#{id}" if id
+
+        uri
+      end
+
+      def full_uri
+        full_uri = @uri
+        query.tap do |q|
+          full_uri += "?#{q}" unless q.empty?
+        end
+
+        full_uri
+      end
+    end
+  end
+end
diff --git a/lib/jsonapi/client/resource.rb b/lib/jsonapi/client/resource.rb
index 0c12227..e554465 100644
--- a/lib/jsonapi/client/resource.rb
+++ b/lib/jsonapi/client/resource.rb
@@ -1,5 +1,5 @@
 module JSONAPI
-  module Client
+  class Client
     class Resource
       attr_reader :id, :type, :attributes, :relationships, :links, :meta
 
diff --git a/lib/jsonapi/client/response.rb b/lib/jsonapi/client/response.rb
new file mode 100644
index 0000000..462b120
--- /dev/null
+++ b/lib/jsonapi/client/response.rb
@@ -0,0 +1,25 @@
+require 'jsonapi/client/document'
+
+module JSONAPI
+  class Client
+    class Response
+      def initialize(http_res)
+        @http_res = http_res
+      end
+
+      def status
+        @http_res.code
+      end
+
+      def headers
+        @http_res.to_hash
+      end
+
+      def body
+        return nil if @http_res.body.nil?
+        json = JSON.parse(@http_res.body)
+        Document.new(json)
+      end
+    end
+  end
+end
diff --git a/spec/client_spec.rb b/spec/client_spec.rb
new file mode 100644
index 0000000..2968ffb
--- /dev/null
+++ b/spec/client_spec.rb
@@ -0,0 +1,13 @@
+require 'jsonapi/client'
+
+describe JSONAPI::Client, '' do
+  it 'works' do
+    client = JSONAPI::Client.new(base_url: 'http://api.example.com')
+
+    client[:users]
+      .include(posts: [:author, comments: [:author]])
+      .fields(posts: [:title, :content], users: [:name, :email])
+      .params(page: 3)
+      .list
+  end
+end
