From d3d775262ff99524f89d3e519c46e281f9147109 Mon Sep 17 00:00:00 2001
From: Roel van Dijk <roel@rustradio.org>
Date: Fri, 28 Sep 2012 21:57:23 +0200
Subject: [PATCH] Raise an error when REST API returns an error.

---
 lib/neography/connection.rb                | 37 ++++++--
 lib/neography/errors.rb                    | 41 +++++++++
 lib/neography/node.rb                      |  9 +-
 lib/neography/relationship.rb              | 15 ++--
 lib/neography/rest.rb                      |  3 +
 spec/integration/node_relationship_spec.rb |  4 +-
 spec/integration/node_spec.rb              | 14 ++--
 spec/integration/rest_batch_spec.rb        | 49 +++++------
 spec/integration/rest_node_spec.rb         | 98 ++++++++++++----------
 spec/integration/rest_path_spec.rb         |  6 +-
 spec/integration/rest_plugin_spec.rb       |  6 ++
 spec/integration/rest_relationship_spec.rb | 61 +++++++-------
 spec/spec_helper.rb                        | 11 +++
 spec/unit/connection_spec.rb               | 68 +++++++++++++++
 14 files changed, 304 insertions(+), 118 deletions(-)
 create mode 100644 lib/neography/errors.rb

diff --git a/lib/neography/connection.rb b/lib/neography/connection.rb
index 84b9054..1649ea0 100644
--- a/lib/neography/connection.rb
+++ b/lib/neography/connection.rb
@@ -98,15 +98,38 @@ def evaluate_response(response)
       when 204
         @logger.debug "OK, no content returned" if @log_enabled
         nil
-      when 400
-        @logger.error "Invalid data sent #{body}" if @log_enabled
-        nil
-      when 404
-        @logger.error "Not Found #{body}" if @log_enabled
+      when 400...500
+        handle_4xx_response(code, body)
         nil
+      end
+    end
+
+    def handle_4xx_response(code, body)
+      parsed_body = JSON.parse(body)
+      message = parsed_body["message"]
+      stacktrace = parsed_body["stacktrace"]
+
+      @logger.error "#{code} error: #{body}" if @log_enabled
+
+      case code
+      when 400, 404
+        case parsed_body["exception"]
+        when "SyntaxException"               ; raise SyntaxException.new(message, code, stacktrace)
+        when "PropertyValueException"        ; raise PropertyValueException.new(message, code, stacktrace)
+        when "BadInputException"             ; raise BadInputException.new(message, code, stacktrace)
+        when "NodeNotFoundException"         ; raise NodeNotFoundException.new(message, code, stacktrace)
+        when "NoSuchPropertyException"       ; raise NoSuchPropertyException.new(message, code, stacktrace)
+        when "RelationshipNotFoundException" ; raise RelationshipNotFoundException.new(message, code, stacktrace)
+        when "NotFoundException"             ; raise NotFoundException.new(message, code, stacktrace)
+        else
+          raise NeographyError.new(message, code, stacktrace)
+        end
+      when 401
+        raise UnauthorizedError.new(message, code, stacktrace)
       when 409
-        @logger.error "Node could not be deleted (still has relationships?)" if @log_enabled
-        nil
+        raise OperationFailureException.new(message, code, stacktrace)
+      else
+        raise NeographyError.new(message, code, stacktrace)
       end
     end
 
diff --git a/lib/neography/errors.rb b/lib/neography/errors.rb
new file mode 100644
index 0000000..fa8a880
--- /dev/null
+++ b/lib/neography/errors.rb
@@ -0,0 +1,41 @@
+module Neography
+
+  class NeographyError < StandardError
+    attr_reader :message, :stacktrace
+
+    def initialize(message = nil, code = nil, stacktrace = nil)
+      @message = message
+      @stacktrace = stacktrace
+    end
+  end
+
+  # HTTP Authentication error
+  class UnauthorizedError < NeographyError; end
+
+  # the Neo4j server Exceptions returned by the REST API:
+
+  # A node could not be found
+  class NodeNotFoundException < NeographyError; end
+
+  # A node cannot be deleted because it has relationships
+  class OperationFailureException < NeographyError; end
+
+  # Properties can not be null
+  class PropertyValueException < NeographyError; end
+
+  # Trying to a delete a property that does not exist
+  class NoSuchPropertyException < NeographyError; end
+
+  # A relationship could not be found
+  class RelationshipNotFoundException < NeographyError; end
+
+  # Error during valid Cypher query
+  class BadInputException < NeographyError; end
+
+  # Invalid Cypher query syntax
+  class SyntaxException < NeographyError; end
+
+  # A path could not be found by node traversal
+  class NotFoundException < NeographyError; end
+
+end
diff --git a/lib/neography/node.rb b/lib/neography/node.rb
index 609f6b3..29592a2 100644
--- a/lib/neography/node.rb
+++ b/lib/neography/node.rb
@@ -32,11 +32,16 @@ def load(node, db = Neography::Rest.new)
     end
 
     def del
-      self.neo_server.delete_node!(self.neo_id)
+      neo_server.delete_node!(self.neo_id)
     end
 
     def exist?
-      !self.neo_server.get_node(self.neo_id).nil?
+      begin
+        neo_server.get_node(self.neo_id)
+        true
+      rescue NodeNotFoundException
+        false
+      end
     end
 
   end
diff --git a/lib/neography/relationship.rb b/lib/neography/relationship.rb
index 0bf5b0e..64e704f 100644
--- a/lib/neography/relationship.rb
+++ b/lib/neography/relationship.rb
@@ -36,23 +36,28 @@ def initialize(hash=nil, server=nil)
       @rel_type = hash["type"]
       neo_server = server
     end
-    
+
     def neo_server
       @neo_server ||= self.start_node.neo_server
     end
-    
+
     def neo_server=(server)
       @neo_server = server
     end
 
     def del
-      self.start_node.neo_server.delete_relationship(self.neo_id)
+      start_node.neo_server.delete_relationship(neo_id)
     end
 
     def exist?
-      !self.start_node.neo_server.get_relationship(self.neo_id).nil?
+      begin
+        start_node.neo_server.get_relationship(neo_id)
+        true
+      rescue Neography::RelationshipNotFoundException
+        false
+      end
     end
-    
+
     def attributes
       attrs = self.methods - OpenStruct.instance_methods - Neography::Relationship.instance_methods
       attrs.values_at(*attrs.each_index.select {|i| i.even?})
diff --git a/lib/neography/rest.rb b/lib/neography/rest.rb
index 7508271..09560c5 100644
--- a/lib/neography/rest.rb
+++ b/lib/neography/rest.rb
@@ -22,6 +22,9 @@
 require 'neography/rest/gremlin'
 require 'neography/rest/batch'
 require 'neography/rest/clean'
+
+require 'neography/errors'
+
 require 'neography/connection'
 
 module Neography
diff --git a/spec/integration/node_relationship_spec.rb b/spec/integration/node_relationship_spec.rb
index aad38ca..f410d2c 100644
--- a/spec/integration/node_relationship_spec.rb
+++ b/spec/integration/node_relationship_spec.rb
@@ -367,7 +367,9 @@ def create_nodes
       p2 = Neography::Node.create
       new_rel = Neography::Relationship.create(:family, p1, p2)
       new_rel.del
-      Neography::Relationship.load(new_rel).should be_nil
+      expect {
+        Neography::Relationship.load(new_rel)
+      }.to raise_error Neography::RelationshipNotFoundException
     end
   end
 
diff --git a/spec/integration/node_spec.rb b/spec/integration/node_spec.rb
index 1bcdb8e..6937e3e 100644
--- a/spec/integration/node_spec.rb
+++ b/spec/integration/node_spec.rb
@@ -44,11 +44,12 @@
       existing_node.neo_id.should == new_node.neo_id
     end
 
-    it "returns nil if it tries to load a node that does not exist" do
+    it "raises an error if it tries to load a node that does not exist" do
       new_node = Neography::Node.create
       fake_node = new_node.neo_id.to_i + 1000
-      existing_node = Neography::Node.load(fake_node)
-      existing_node.should be_nil
+      expect {
+        existing_node = Neography::Node.load(fake_node)
+      }.to raise_error Neography::NodeNotFoundException
     end
 
     it "can load a node that exists not on the default rest server" do
@@ -74,15 +75,16 @@
       new_node = Neography::Node.create
       node_id = new_node.neo_id
       new_node.del
-      deleted_node = Neography::Node.load(node_id)
-      deleted_node.should be_nil
+      expect {
+        Neography::Node.load(node_id)
+      }.to raise_error Neography::NodeNotFoundException
     end
   end
 
   describe "exists?" do
     it "can tell if it exists" do
       new_node = Neography::Node.create
-      new_node.exist?.should be_true 
+      new_node.exist?.should be_true
     end
 
     it "can tell if does not exists" do
diff --git a/spec/integration/rest_batch_spec.rb b/spec/integration/rest_batch_spec.rb
index 59855e9..e35a888 100644
--- a/spec/integration/rest_batch_spec.rb
+++ b/spec/integration/rest_batch_spec.rb
@@ -16,7 +16,7 @@
       batch_result.first.should have_key("from")
       batch_result.first["body"]["self"].split('/').last.should == new_node[:id]
     end
-    
+
     it "can get multiple nodes" do
       node1 = @neo.create_node
       node1[:id] = node1["self"].split('/').last
@@ -133,7 +133,7 @@
       batch_result.first["body"]["end"].split('/').last.should == node2["self"].split('/').last
       batch_result.first["body"]["self"].should == new_relationship["self"]
     end
-    
+
     it "can create a single relationship" do
       node1 = @neo.create_node
       node2 = @neo.create_node
@@ -205,14 +205,13 @@
       new_node = @neo.create_node
       key = generate_text(6)
       value = generate_text
-      new_index = @neo.get_node_index(index_name, key, value) 
       batch_result = @neo.batch [:add_node_to_index, index_name, key, value, new_node]
       batch_result.first.should have_key("id")
       batch_result.first.should have_key("from")
-      existing_index = @neo.find_node_index(index_name, key, value) 
+      existing_index = @neo.find_node_index(index_name, key, value)
       existing_index.should_not be_nil
       existing_index.first["self"].should == new_node["self"]
-      @neo.remove_node_from_index(index_name, key, value, new_node) 
+      @neo.remove_node_from_index(index_name, key, value, new_node)
     end
 
     it "can get a node index" do
@@ -251,7 +250,7 @@
       batch_result.first.should have_key("id")
       batch_result.first.should have_key("from")
       batch_result.first["body"]["self"].split('/').last.should == "0"
-    end  
+    end
 
     it "can batch gremlin with parameters" do
       new_node = @neo.create_node
@@ -260,14 +259,14 @@
       batch_result.first.should have_key("id")
       batch_result.first.should have_key("from")
       batch_result.first["body"]["self"].split('/').last.should == id
-    end  
+    end
 
     it "can batch cypher" do
       batch_result = @neo.batch [:execute_query, "start n=node(0) return n"]
       batch_result.first.should have_key("id")
       batch_result.first.should have_key("from")
       batch_result.first["body"]["data"][0][0]["self"].split('/').last.should == "0"
-    end  
+    end
 
     it "can batch cypher with parameters" do
       new_node = @neo.create_node
@@ -276,18 +275,20 @@
       batch_result.first.should have_key("id")
       batch_result.first.should have_key("from")
       batch_result.first["body"]["data"][0][0]["self"].split('/').last.should == id
-    end  
-  
+    end
+
 	it "can delete a node in batch" do
-		
 		node1 = @neo.create_node
 		node2 = @neo.create_node
 		id1 = node1['self'].split('/').last
 		id2 = node2['self'].split('/').last
 		batch_result = @neo.batch [:delete_node, id1 ], [:delete_node, id2]
-		@neo.get_node(node1).should be_nil
-		@neo.get_node(node2).should be_nil
-
+    expect {
+      @neo.get_node(node1).should be_nil
+    }.to raise_error Neography::NodeNotFoundException
+    expect {
+      @neo.get_node(node2).should be_nil
+    }.to raise_error Neography::NodeNotFoundException
 	end
 
 	it "can remove a node from an index in batch " do
@@ -295,16 +296,16 @@
 		key = generate_text(6)
 		value1 = generate_text
 		value2 = generate_text
-		value3 = generate_text  
-		
+		value3 = generate_text
+
 		node1 = @neo.create_unique_node(index, key, value1, { "name" => "Max" })
 		node2 = @neo.create_unique_node(index, key, value2, { "name" => "Neo" }) 
 		node3 = @neo.create_unique_node(index, key, value3, { "name" => "Samir"})
-		
+
 		batch_result = @neo.batch [:remove_node_from_index, index, key, value1, node1 ], 
 		                          [:remove_node_from_index, index, key, node2 ],
 		                          [:remove_node_from_index, index, node3 ]
-		
+
 		@neo.get_node_index(index, key, value1).should be_nil
 		@neo.get_node_index(index, key, value2).should be_nil
 		@neo.get_node_index(index, key, value3).should be_nil
@@ -398,12 +399,12 @@
       key = generate_text(6)
       value = generate_text
 
-      batch_result = @neo.batch [:create_node, {"name" => "Max"}], 
-                                [:create_node, {"name" => "Marc"}],                           
+      batch_result = @neo.batch [:create_node, {"name" => "Max"}],
+                                [:create_node, {"name" => "Marc"}],
                                 [:add_node_to_index, "test_node_index", key, value, "{0}"]
                                 [:add_node_to_index, "test_node_index", key, value, "{1}"]
-                                [:create_relationship, "friends", "{0}", "{1}", {:since => "college"}]                        
-                                [:add_relationship_to_index, "test_relationship_index", key, value, "{4}"] 
+                                [:create_relationship, "friends", "{0}", "{1}", {:since => "college"}]
+                                [:add_relationship_to_index, "test_relationship_index", key, value, "{4}"]
       batch_result.should_not be_nil
     end
 
@@ -428,7 +429,7 @@
       batch_result = @neo.batch [:create_node, {:street1=>"94437 Kemmer Crossing", :street2=>"Apt. 333", :city=>"Abshireton", :state=>"AA", :zip=>"65820", :_type=>"Address", :created_at=>1335269478}],
                                 [:add_node_to_index, "person_ssn", "ssn", "000-00-0001", "{0}"],
                                 [:create_unique_node, "person", "ssn", "000-00-0001", {:first_name=>"Jane", :last_name=>"Doe", :ssn=>"000-00-0001", :_type=>"Person", :created_at=>1335269478}],
-                                [:create_relationship, "has", "{0}", "{2}", {}]   
+                                [:create_relationship, "has", "{0}", "{2}", {}]
       batch_result.should_not be_nil
 
 
@@ -442,5 +443,5 @@
     end
 
   end
-  
+
 end
diff --git a/spec/integration/rest_node_spec.rb b/spec/integration/rest_node_spec.rb
index 6022efc..8e271b3 100644
--- a/spec/integration/rest_node_spec.rb
+++ b/spec/integration/rest_node_spec.rb
@@ -64,11 +64,12 @@
       existing_node["self"].split('/').last.should == new_node[:id]
     end
 
-    it "returns nil if it tries to get a node that does not exist" do
+    it "raises an error if it tries to get a node that does not exist" do
       new_node = @neo.create_node
       fake_node = new_node["self"].split('/').last.to_i + 1000
-      existing_node = @neo.get_node(fake_node)
-      existing_node.should be_nil
+      expect {
+        @neo.get_node(fake_node)
+      }.to raise_error Neography::NodeNotFoundException
     end
   end
 
@@ -84,9 +85,9 @@
     it "it fails to set properties on a node that does not exist" do
       new_node = @neo.create_node
       fake_node = new_node["self"].split('/').last.to_i + 1000
-      @neo.set_node_properties(fake_node, {"weight" => 150, "hair" => "blonde"})
-      node_properties = @neo.get_node_properties(fake_node)
-      node_properties.should be_nil
+      expect {
+        @neo.set_node_properties(fake_node, {"weight" => 150, "hair" => "blonde"})
+      }.to raise_error Neography::NodeNotFoundException
     end
   end
 
@@ -104,9 +105,9 @@
     it "it fails to reset properties on a node that does not exist" do
       new_node = @neo.create_node
       fake_node = new_node["self"].split('/').last.to_i + 1000
-      @neo.reset_node_properties(fake_node, {"weight" => 170, "eyes" => "green"})
-      node_properties = @neo.get_node_properties(fake_node)
-      node_properties.should be_nil
+      expect {
+        @neo.reset_node_properties(fake_node, {"weight" => 170, "eyes" => "green"})
+      }.to raise_error Neography::NodeNotFoundException
     end
   end
 
@@ -131,15 +132,19 @@
       @neo.get_node_properties(new_node).should be_nil
     end
 
-    it "returns nil if it tries to get some of the properties on a node that does not have any" do
+    it "raises error if it tries to get some of the properties on a node that does not have any" do
       new_node = @neo.create_node
-      @neo.get_node_properties(new_node, ["weight", "height"]).should be_nil
+      expect {
+        @neo.get_node_properties(new_node, ["weight", "height"]).should be_nil
+      }.to raise_error Neography::NoSuchPropertyException
     end
 
-    it "returns nil if it fails to get properties on a node that does not exist" do
+    it "raises error if it fails to get properties on a node that does not exist" do
       new_node = @neo.create_node
       fake_node = new_node["self"].split('/').last.to_i + 1000
-      @neo.get_node_properties(fake_node).should be_nil
+      expect {
+        @neo.get_node_properties(fake_node).should be_nil
+      }.to raise_error Neography::NodeNotFoundException
     end
   end
 
@@ -150,10 +155,12 @@
       @neo.get_node_properties(new_node).should be_nil
     end
 
-    it "returns nil if it fails to remove the properties of a node that does not exist" do
+    it "raises error if it fails to remove the properties of a node that does not exist" do
       new_node = @neo.create_node
       fake_node = new_node["self"].split('/').last.to_i + 1000
-      @neo.remove_node_properties(fake_node).should be_nil
+      expect {
+        @neo.remove_node_properties(fake_node).should be_nil
+      }.to raise_error Neography::NodeNotFoundException
     end
 
     it "can remove a specific node property" do
@@ -177,35 +184,39 @@
     it "can delete an unrelated node" do
       new_node = @neo.create_node
       @neo.delete_node(new_node).should be_nil
-      existing_node = @neo.get_node(new_node)
-      existing_node.should be_nil
+      expect {
+        @neo.get_node(new_node)
+      }.to raise_error Neography::NodeNotFoundException
     end
 
     it "cannot delete a node that has relationships" do
       new_node1 = @neo.create_node
       new_node2 = @neo.create_node
       @neo.create_relationship("friends", new_node1, new_node2)
-      @neo.delete_node(new_node1).should be_nil
+      expect {
+        @neo.delete_node(new_node1).should be_nil
+      }.to raise_error Neography::OperationFailureException
       existing_node = @neo.get_node(new_node1)
       existing_node.should_not be_nil
     end
 
-    it "returns nil if it tries to delete a node that does not exist" do
+    it "raises error if it tries to delete a node that does not exist" do
       new_node = @neo.create_node
       fake_node = new_node["self"].split('/').last.to_i + 1000
-      @neo.delete_node(fake_node).should be_nil
-      existing_node = @neo.get_node(fake_node)
-      existing_node.should be_nil
+      expect {
+        @neo.delete_node(fake_node).should be_nil
+      }.to raise_error Neography::NodeNotFoundException
     end
 
-    it "returns nil if it tries to delete a node that has already been deleted" do
+    it "raises error if it tries to delete a node that has already been deleted" do
       new_node = @neo.create_node
       @neo.delete_node(new_node).should be_nil
-      existing_node = @neo.get_node(new_node)
-      existing_node.should be_nil
-      @neo.delete_node(new_node).should be_nil
-      existing_node = @neo.get_node(new_node)
-      existing_node.should be_nil
+      expect {
+        existing_node = @neo.get_node(new_node)
+      }.to raise_error Neography::NodeNotFoundException
+      expect {
+        @neo.delete_node(new_node).should be_nil
+      }.to raise_error Neography::NodeNotFoundException
     end
   end
 
@@ -213,8 +224,9 @@
     it "can delete an unrelated node" do
       new_node = @neo.create_node
       @neo.delete_node!(new_node).should be_nil
-      existing_node = @neo.get_node(new_node)
-      existing_node.should be_nil
+      expect {
+        existing_node = @neo.get_node(new_node)
+      }.to raise_error Neography::NodeNotFoundException
     end
 
     it "can delete a node that has relationships" do
@@ -222,26 +234,28 @@
       new_node2 = @neo.create_node
       @neo.create_relationship("friends", new_node1, new_node2)
       @neo.delete_node!(new_node1).should be_nil
-      existing_node = @neo.get_node(new_node1)
-      existing_node.should be_nil
+      expect {
+        existing_node = @neo.get_node(new_node1)
+      }.to raise_error Neography::NodeNotFoundException
     end
 
-    it "returns nil if it tries to delete a node that does not exist" do
+    it "raises error if it tries to delete a node that does not exist" do
       new_node = @neo.create_node
       fake_node = new_node["self"].split('/').last.to_i + 1000
-      @neo.delete_node!(fake_node).should be_nil
-      existing_node = @neo.get_node(fake_node)
-      existing_node.should be_nil
+      expect {
+        @neo.delete_node!(fake_node).should be_nil
+      }.to raise_error Neography::NodeNotFoundException
     end
 
-    it "returns nil if it tries to delete a node that has already been deleted" do
+    it "raises error if it tries to delete a node that has already been deleted" do
       new_node = @neo.create_node
       @neo.delete_node!(new_node).should be_nil
-      existing_node = @neo.get_node(new_node)
-      existing_node.should be_nil
-      @neo.delete_node!(new_node).should be_nil
-      existing_node = @neo.get_node(new_node)
-      existing_node.should be_nil
+      expect {
+        existing_node = @neo.get_node(new_node)
+      }.to raise_error Neography::NodeNotFoundException
+      expect {
+        @neo.delete_node!(new_node).should be_nil
+      }.to raise_error Neography::NodeNotFoundException
     end
   end
 
diff --git a/spec/integration/rest_path_spec.rb b/spec/integration/rest_path_spec.rb
index 37806a9..79a10cc 100644
--- a/spec/integration/rest_path_spec.rb
+++ b/spec/integration/rest_path_spec.rb
@@ -83,9 +83,9 @@
       @neo.create_relationship("friends", new_node3, new_node4)
       @neo.create_relationship("friends", new_node4, new_node5)
       @neo.create_relationship("friends", new_node3, new_node5)
-      path = @neo.get_path(new_node1, new_node5, {"type"=> "friends", "direction" => "out"}, depth=2, algorithm="shortestPath")
-      path["start"].should be_nil
-      path["end"].should be_nil
+      expect {
+        @neo.get_path(new_node1, new_node5, {"type"=> "friends", "direction" => "out"}, depth=2, algorithm="shortestPath")
+      }.to raise_error Neography::NotFoundException
     end
 
     it "can get a path between two nodes of a specific relationship" do
diff --git a/spec/integration/rest_plugin_spec.rb b/spec/integration/rest_plugin_spec.rb
index f089109..839ed97 100644
--- a/spec/integration/rest_plugin_spec.rb
+++ b/spec/integration/rest_plugin_spec.rb
@@ -62,6 +62,12 @@
       existing_node["data"][0][0]["self"].split('/').last.should == id
     end
 
+    it "throws an error for an invalid query" do
+      expect {
+        @neo.execute_query("this is not a query")
+      }.to raise_error(Neography::SyntaxException)
+    end
+
   end
 
 end
diff --git a/spec/integration/rest_relationship_spec.rb b/spec/integration/rest_relationship_spec.rb
index 73fe00d..fa90edd 100644
--- a/spec/integration/rest_relationship_spec.rb
+++ b/spec/integration/rest_relationship_spec.rb
@@ -30,7 +30,7 @@
       new_relationship["data"]["since"].should == '10-1-2010'
       new_relationship["data"]["met"].should == "college"
     end
-    
+
     it "can create a unique node with more than one property" do
       index_name = generate_text(6)
       key = generate_text(6)
@@ -40,7 +40,7 @@
       new_node["data"]["name"].should == "Max"
       new_node["data"]["age"].should == 31
     end
-    
+
     it "can create a unique relationship" do
       index_name = generate_text(6)
       key = generate_text(6)
@@ -51,7 +51,6 @@
       new_relationship["data"][key].should == value
     end
 
-    
   end
 
   describe "get_relationship" do
@@ -65,13 +64,14 @@
       existing_relationship["self"].should == new_relationship["self"]
     end
 
-    it "returns nil if it tries to get a relationship that does not exist" do
+    it "raises error if it tries to get a relationship that does not exist" do
       new_node1 = @neo.create_node
       new_node2 = @neo.create_node
       new_relationship = @neo.create_relationship("friends", new_node1, new_node2)
       fake_relationship = new_relationship["self"].split('/').last.to_i + 1000
-      existing_relationship = @neo.get_relationship(fake_relationship)
-      existing_relationship.should be_nil
+      expect {
+        existing_relationship = @neo.get_relationship(fake_relationship)
+      }.to raise_error Neography::RelationshipNotFoundException
     end
   end
 
@@ -93,9 +93,9 @@
       new_node2 = @neo.create_node
       new_relationship = @neo.create_relationship("friends", new_node1, new_node2)
       fake_relationship = new_relationship["self"].split('/').last.to_i + 1000
-      @neo.set_relationship_properties(fake_relationship, {"since" => '10-1-2010', "met" => "college"})
-      relationship_properties = @neo.get_relationship_properties(fake_relationship)
-      relationship_properties.should be_nil
+      expect {
+        @neo.set_relationship_properties(fake_relationship, {"since" => '10-1-2010', "met" => "college"})
+      }.to raise_error Neography::RelationshipNotFoundException
     end
   end
 
@@ -117,9 +117,9 @@
       new_node2 = @neo.create_node
       new_relationship = @neo.create_relationship("friends", new_node1, new_node2)
       fake_relationship = new_relationship["self"].split('/').last.to_i + 1000
-      @neo.reset_relationship_properties(fake_relationship, {"since" => '10-1-2010', "met" => "college"})
-      relationship_properties = @neo.get_relationship_properties(fake_relationship)
-      relationship_properties.should be_nil
+      expect {
+        @neo.reset_relationship_properties(fake_relationship, {"since" => '10-1-2010', "met" => "college"})
+      }.to raise_error Neography::RelationshipNotFoundException
     end
   end
 
@@ -151,21 +151,23 @@
       relationship_properties.should be_nil
     end
 
-    it "returns nil if it tries to get some of the properties on a relationship that does not have any" do
+    it "raises error if it tries to get some of the properties on a relationship that does not have any" do
       new_node1 = @neo.create_node
       new_node2 = @neo.create_node
       new_relationship = @neo.create_relationship("friends", new_node1, new_node2)
-      relationship_properties = @neo.get_relationship_properties(new_relationship, ["since", "roommates"])
-      relationship_properties.should be_nil
+      expect {
+        @neo.get_relationship_properties(new_relationship, ["since", "roommates"])
+      }.to raise_error Neography::NoSuchPropertyException
     end
 
-    it "returns nil if it fails to get properties on a relationship that does not exist" do
+    it "raises error if it fails to get properties on a relationship that does not exist" do
       new_node1 = @neo.create_node
       new_node2 = @neo.create_node
       new_relationship = @neo.create_relationship("friends", new_node1, new_node2)
       fake_relationship = new_relationship["self"].split('/').last.to_i + 1000
-      relationship_properties = @neo.get_relationship_properties(fake_relationship)
-      relationship_properties.should be_nil
+      expect {
+        @neo.get_relationship_properties(fake_relationship)
+      }.to raise_error Neography::RelationshipNotFoundException
     end
   end
 
@@ -178,13 +180,14 @@
       @neo.get_relationship_properties(new_relationship).should be_nil
     end
 
-    it "returns nil if it fails to remove the properties of a relationship that does not exist" do
+    it "raises error if it fails to remove the properties of a relationship that does not exist" do
       new_node1 = @neo.create_node
       new_node2 = @neo.create_node
       new_relationship = @neo.create_relationship("friends", new_node1, new_node2, {"since" => '10-1-2010', "met" => "college"})
       fake_relationship = new_relationship["self"].split('/').last.to_i + 1000
-      @neo.remove_relationship_properties(fake_relationship).should be_nil
-      @neo.get_relationship_properties(fake_relationship).should be_nil
+      expect {
+        @neo.remove_relationship_properties(fake_relationship)
+      }.to raise_error Neography::RelationshipNotFoundException
     end
 
     it "can remove a specific relationship property" do
@@ -192,7 +195,7 @@
       new_node2 = @neo.create_node
       new_relationship = @neo.create_relationship("friends", new_node1, new_node2, {"since" => '10-1-2010', "met" => "college"})
       @neo.remove_relationship_properties(new_relationship, "met")
-      relationship_properties = @neo.get_relationship_properties(new_relationship, ["met", "since"])
+      relationship_properties = @neo.get_relationship_properties(new_relationship)
       relationship_properties["met"].should be_nil
       relationship_properties["since"].should == '10-1-2010'
     end
@@ -202,7 +205,7 @@
       new_node2 = @neo.create_node
       new_relationship = @neo.create_relationship("friends", new_node1, new_node2, {"since" => '10-1-2010', "met" => "college", "roommates" => "no"})
       @neo.remove_relationship_properties(new_relationship, ["met", "since"])
-      relationship_properties = @neo.get_relationship_properties(new_relationship, ["since", "met", "roommates"])
+      relationship_properties = @neo.get_relationship_properties(new_relationship)
       relationship_properties["met"].should be_nil
       relationship_properties["since"].should be_nil
       relationship_properties["roommates"].should == "no"
@@ -219,13 +222,14 @@
       relationships.should be_nil
     end
 
-    it "returns nil if it tries to delete a relationship that does not exist" do
+    it "raises error if it tries to delete a relationship that does not exist" do
       new_node1 = @neo.create_node
       new_node2 = @neo.create_node
       new_relationship = @neo.create_relationship("friends", new_node1, new_node2, {"since" => '10-1-2010', "met" => "college"})
       fake_relationship = new_relationship["self"].split('/').last.to_i + 1000
-      existing_relationship = @neo.delete_relationship(fake_relationship)
-      existing_relationship.should be_nil
+      expect {
+        existing_relationship = @neo.delete_relationship(fake_relationship)
+      }.to raise_error Neography::RelationshipNotFoundException
     end
 
     it "returns nil if it tries to delete a relationship that has already been deleted" do
@@ -234,8 +238,9 @@
       new_relationship = @neo.create_relationship("friends", new_node1, new_node2, {"since" => '10-1-2010', "met" => "college"})
       existing_relationship = @neo.delete_relationship(new_relationship)
       existing_relationship.should be_nil
-      existing_relationship = @neo.delete_relationship(new_relationship)
-      existing_relationship.should be_nil
+      expect {
+        existing_relationship = @neo.delete_relationship(new_relationship)
+      }.to raise_error Neography::RelationshipNotFoundException
     end
   end
 
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 755d9fe..34ab71a 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -23,3 +23,14 @@ def json_content_type
   {"Content-Type"=>"application/json"}
 end
 
+def error_response(attributes)
+  stub(
+    code: attributes[:code],
+    body: {
+    message:   attributes[:message],
+    exception: attributes[:exception],
+    stacktrace: attributes[:stacktrace]
+  }.reject { |k,v| v.nil? }.to_json
+  )
+end
+
diff --git a/spec/unit/connection_spec.rb b/spec/unit/connection_spec.rb
index 068de86..330d10c 100644
--- a/spec/unit/connection_spec.rb
+++ b/spec/unit/connection_spec.rb
@@ -130,6 +130,74 @@ module Neography
         connection.get("/foo/bar", :headers => {})
       end
 
+      context "errors" do
+
+        it "raises NodeNotFoundException" do
+          response = error_response(code: 404, message: "a message", exception: "NodeNotFoundException")
+          HTTParty.stub(:get).and_return(response)
+          expect {
+            connection.get("/foo/bar")
+          }.to raise_error NodeNotFoundException
+        end
+
+        it "raises OperationFailureException" do
+          response = error_response(code: 409, message: "a message", exception: "OperationFailureException")
+          HTTParty.stub(:get).and_return(response)
+          expect {
+            connection.get("/foo/bar")
+          }.to raise_error OperationFailureException
+        end
+
+        it "raises PropertyValueException" do
+          response = error_response(code: 400, message: "a message", exception: "PropertyValueException")
+          HTTParty.stub(:get).and_return(response)
+          expect {
+            connection.get("/foo/bar")
+          }.to raise_error PropertyValueException
+        end
+
+        it "raises NoSuchPropertyException" do
+          response = error_response(code: 404, message: "a message", exception: "NoSuchPropertyException")
+          HTTParty.stub(:get).and_return(response)
+          expect {
+            connection.get("/foo/bar")
+          }.to raise_error NoSuchPropertyException
+        end
+
+        it "raises RelationshipNotFoundException" do
+          response = error_response(code: 404, message: "a message", exception: "RelationshipNotFoundException")
+          HTTParty.stub(:get).and_return(response)
+          expect {
+            connection.get("/foo/bar")
+          }.to raise_error RelationshipNotFoundException
+        end
+
+        it "raises BadInputException" do
+          response = error_response(code: 400, message: "a message", exception: "BadInputException")
+          HTTParty.stub(:get).and_return(response)
+          expect {
+            connection.get("/foo/bar")
+          }.to raise_error BadInputException
+        end
+
+        it "raises UnauthorizedError" do
+          response = error_response(code: 401)
+          HTTParty.stub(:get).and_return(response)
+          expect {
+            connection.get("/foo/bar")
+          }.to raise_error UnauthorizedError
+        end
+
+        it "raises NeographyError in all other cases" do
+          response = error_response(code: 418, message: "I'm a teapot.")
+          HTTParty.stub(:get).and_return(response)
+          expect {
+            connection.get("/foo/bar")
+          }.to raise_error NeographyError
+        end
+
+      end
+
     end
   end
 end