I am Hack Sparrow
Captain of the Internets.

Neo4j Tutorial – REST API

Using the Neo4j REST API


After starting the Neo4j server, load the HTTP console by clicking here. The HTTP console uses the Neo4j REST API to interact with the database. Even though you can use the HTTP shell for manually interacting with the database, it is best used for prototyping the REST calls your app would be making to the database. Unless Neo4j provides bindings for your language (Java, Python, Ruby), you will most probably be using the REST API to talk to the database.

For your reference, the Neo4j documentation is located at http://docs.neo4j.org/chunked/stable/.

Let's see how some of the common operations can be performed in Neo4j Nodes and Relationships using the REST API.

To create a node

POST http://localhost:7474/db/data/node
==> 201 Created
==> {
==> "outgoing_relationships" : "http://localhost:7474/db/data/node/26/relationships/out",
==> "data" : {
==> },
==> "traverse" : "http://localhost:7474/db/data/node/26/traverse/{returnType}",
==> "all_typed_relationships" : "http://localhost:7474/db/data/node/26/relationships/all/{-list|&|types}",
==> "property" : "http://localhost:7474/db/data/node/26/properties/{key}",
==> "self" : "http://localhost:7474/db/data/node/26",
==> "properties" : "http://localhost:7474/db/data/node/26/properties",
==> "outgoing_typed_relationships" : "http://localhost:7474/db/data/node/26/relationships/out/{-list|&|types}",
==> "incoming_relationships" : "http://localhost:7474/db/data/node/26/relationships/in",
==> "extensions" : {
==> },
==> "create_relationship" : "http://localhost:7474/db/data/node/26/relationships",
==> "paged_traverse" : "http://localhost:7474/db/data/node/26/paged/traverse/{returnType}{?pageSize,leaseTime}",
==> "all_relationships" : "http://localhost:7474/db/data/node/26/relationships/all",
==> "incoming_typed_relationships" : "http://localhost:7474/db/data/node/26/relationships/in/{-list|&|types}"
==> }

The above command creates an empty node, with no properties, except for a reference id to itself. In the above example the node id is 26. The REST API uses the HTTP protocol; the "201 Created" message you see is a HTTP status code.

You can also specify the properties of a node as it's being created by passing an additional JSON object.

POST http://localhost:7474/db/data/node {"name":"Archie"}
==> 201 Created
==> {
==> "outgoing_relationships" : "http://localhost:7474/db/data/node/27/relationships/out",
==> "data" : {
==> "name" : "Archie"
==> },
==> "traverse" : "http://localhost:7474/db/data/node/27/traverse/{returnType}",
==> "all_typed_relationships" : "http://localhost:7474/db/data/node/27/relationships/all/{-list|&|types}",
==> "property" : "http://localhost:7474/db/data/node/27/properties/{key}",
==> "self" : "http://localhost:7474/db/data/node/27",
==> "properties" : "http://localhost:7474/db/data/node/27/properties",
==> "outgoing_typed_relationships" : "http://localhost:7474/db/data/node/27/relationships/out/{-list|&|types}",
==> "incoming_relationships" : "http://localhost:7474/db/data/node/27/relationships/in",
==> "extensions" : {
==> },
==> "create_relationship" : "http://localhost:7474/db/data/node/27/relationships",
==> "paged_traverse" : "http://localhost:7474/db/data/node/27/paged/traverse/{returnType}{?pageSize,leaseTime}",
==> "all_relationships" : "http://localhost:7474/db/data/node/27/relationships/all",
==> "incoming_typed_relationships" : "http://localhost:7474/db/data/node/27/relationships/in/{-list|&|types}"
==> }

Make sure the JSON object adheres to the JSON specification, else you will encounter an invalid JSON data error message. For example {name:"Archie"} is invalid because the property should also be quoted according to the JSON specs. Also according to the JSON specs, you should use the double quote character (") for quoting strings, and not the single quote (').

If you look at the return object of the above command, you can see that it contains the URLs to the node (self) and its properties, among other information related to the node.

To read a node

Once you have the node id, you can get a node this way:

GET http://localhost:7474/db/data/node/27
==> 200 OK
==> {
==> "outgoing_relationships" : "http://localhost:7474/db/data/node/27/relationships/out",
==> "data" : {
==> "name" : "Archie"
==> },
==> "traverse" : "http://localhost:7474/db/data/node/27/traverse/{returnType}",
==> "all_typed_relationships" : "http://localhost:7474/db/data/node/27/relationships/all/{-list|&|types}",
==> "property" : "http://localhost:7474/db/data/node/27/properties/{key}",
==> "self" : "http://localhost:7474/db/data/node/27",
==> "properties" : "http://localhost:7474/db/data/node/27/properties",
==> "outgoing_typed_relationships" : "http://localhost:7474/db/data/node/27/relationships/out/{-list|&|types}",
==> "incoming_relationships" : "http://localhost:7474/db/data/node/27/relationships/in",
==> "extensions" : {
==> },
==> "create_relationship" : "http://localhost:7474/db/data/node/27/relationships",
==> "paged_traverse" : "http://localhost:7474/db/data/node/27/paged/traverse/{returnType}{?pageSize,leaseTime}",
==> "all_relationships" : "http://localhost:7474/db/data/node/27/relationships/all",
==> "incoming_typed_relationships" : "http://localhost:7474/db/data/node/27/relationships/in/{-list|&|types}"
==> }

Trying to get a none existent node will result in HTTP 404 error:

GET http://localhost:7474/db/data/node/10303371
==> 404 Not Found
==> {
==> "message" : "Cannot find node with id [10303371] in database.",
==> "exception" : "org.neo4j.server.rest.web.NodeNotFoundException: Cannot find node with id [10303371] in database.",
==> "stacktrace" : [ "org.neo4j.server.rest.web.DatabaseActions.node(DatabaseActions.java:112)", "org.neo4j.server.rest.web.DatabaseActions.getNode(DatabaseActions.java:223)", "org.neo4j.server.rest.web.RestfulGraphDatabase.getNode(RestfulGraphDatabase.java:202)", "sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)", "sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)", "sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)", "java.lang.reflect.Method.invoke(Method.java:597)", "com.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60)", "com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$ResponseOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:205)", "com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75)", "com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:288)", "com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)", "com.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:108)", "com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)", "com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:84)", "com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1469)", "com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1400)", "com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1349)", "com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1339)", "com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:416)", "com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:537)", "com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:699)", "javax.servlet.http.HttpServlet.service(HttpServlet.java:820)", "org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)", "org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)", "org.neo4j.server.web.LimitRequestTimeFilter.doFilter(LimitRequestTimeFilter.java:64)", "org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)", "org.neo4j.server.statistic.StatisticFilter.doFilter(StatisticFilter.java:62)", "org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)", "org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)", "org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)", "org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)", "org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:114)", "org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)", "org.mortbay.jetty.Server.handle(Server.java:326)", "org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)", "org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:926)", "org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:549)", "org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212)", "org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)", "org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:410)", "org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)" ]
==> }

To delete a node

Deleting a node is pretty straightforward, just call the HTTP DELETE method on the node id:

DELETE http://localhost:7474/db/data/node/26
==> 204 No Content

Note: nodes with relationships cannot be deleted. To demonstrate that, let's create another node:

POST http://localhost:7474/db/data/node {"name":"Veronica"}

and create a relationship:

POST http://localhost:7474/db/data/node/27/relationships {"to" : "http://localhost:7474/db/data/node/28", "type" : "LOVES"}
==> 201 Created
==> {
==> "start" : "http://localhost:7474/db/data/node/27",
==> "data" : {
==> },
==> "self" : "http://localhost:7474/db/data/relationship/1",
==> "property" : "http://localhost:7474/db/data/relationship/1/properties/{key}",
==> "properties" : "http://localhost:7474/db/data/relationship/1/properties",
==> "type" : "LOVES",
==> "extensions" : {
==> },
==> "end" : "http://localhost:7474/db/data/node/28"
==> }

Note that each relationship we create has its own id too. The relationship id is required for referring, updating and deleting the relationship. Now that we have created an outgoing relationship between nodes 27 and 28, let's try deleting node 27:

DELETE http://localhost:7474/db/data/node/27
==> 409 Conflict
==> {
==> "message" : "The node with id 27 cannot be deleted. Check that the node is orphaned before deletion.",
==> "exception" : "org.neo4j.server.rest.web.OperationFailureException: The node with id 27 cannot be deleted. Check that the node is orphaned before deletion.",
==> "stacktrace" : [ "org.neo4j.server.rest.web.DatabaseActions.deleteNode(DatabaseActions.java:244)", "org.neo4j.server.rest.web.RestfulGraphDatabase.deleteNode(RestfulGraphDatabase.java:216)", "sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)", "sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)", "sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)", "java.lang.reflect.Method.invoke(Method.java:597)", "com.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60)", "com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$ResponseOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:205)", "com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75)", "com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:288)", "com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)", "com.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:108)", "com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)", "com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:84)", "com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1469)", "com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1400)", "com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1349)", "com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1339)", "com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:416)", "com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:537)", "com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:699)", "javax.servlet.http.HttpServlet.service(HttpServlet.java:820)", "org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)", "org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)", "org.neo4j.server.web.LimitRequestTimeFilter.doFilter(LimitRequestTimeFilter.java:64)", "org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)", "org.neo4j.server.statistic.StatisticFilter.doFilter(StatisticFilter.java:62)", "org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)", "org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)", "org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)", "org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)", "org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:114)", "org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)", "org.mortbay.jetty.Server.handle(Server.java:326)", "org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)", "org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:926)", "org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:549)", "org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212)", "org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)", "org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:410)", "org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)" ]
==> }

There it is. It failed to delete. We need to delete all the relationships on node 27 before we can delete it. Here is how we delete the relationship we created:

DELETE http://localhost:7474/db/data/relationship/1
==> 204 No Content

With the relationship deleted, let's try deleting the node once more:

DELETE http://localhost:7474/db/data/node/27
==> 204 No Content

This time it's gone. Deleted.

May sound strange, but there is no specific command to delete all the nodes in a graph. You have to walk all the nodes, delete the relationships, and delete the nodes thereafter.

To continue with the examples, we'll need Archie. So let's create a new node and give it the name Archie.

POST http://localhost:7474/db/data/node {"name":"Archie"}
==> 201 Created
==> {
==> "outgoing_relationships" : "http://localhost:7474/db/data/node/29/relationships/out",
==> "data" : {
==> "name" : "Archie"
==> },
==> "traverse" : "http://localhost:7474/db/data/node/29/traverse/{returnType}",
==> "all_typed_relationships" : "http://localhost:7474/db/data/node/29/relationships/all/{-list|&|types}",
==> "property" : "http://localhost:7474/db/data/node/29/properties/{key}",
==> "self" : "http://localhost:7474/db/data/node/29",
==> "properties" : "http://localhost:7474/db/data/node/29/properties",
==> "outgoing_typed_relationships" : "http://localhost:7474/db/data/node/29/relationships/out/{-list|&|types}",
==> "incoming_relationships" : "http://localhost:7474/db/data/node/29/relationships/in",
==> "extensions" : {
==> },
==> "create_relationship" : "http://localhost:7474/db/data/node/29/relationships",
==> "paged_traverse" : "http://localhost:7474/db/data/node/29/paged/traverse/{returnType}{?pageSize,leaseTime}",
==> "all_relationships" : "http://localhost:7474/db/data/node/29/relationships/all",
==> "incoming_typed_relationships" : "http://localhost:7474/db/data/node/29/relationships/in/{-list|&|types}"
==> }

From here on, node id 29 is Archie.

To add properties to a node

Let's give Archie an age:

PUT http://localhost:7474/db/data/node/29/properties/age 17
==> 204 No Content

Don't be alarmed by "204 No Content", it means the operation was successful, but the server did not return any content. Anyway, let's confirm that the property is actually created.

GET http://localhost:7474/db/data/node/29/properties
==> 200 OK
==> {
==> "age" : 17,
==> "name" : "Archie"
==> }

There it is, node 29 now has a new property called age with the value of 17.

What if you wanted to set a whole bunch of properties at one go? Here is how you do that:

PUT http://localhost:7474/db/data/node/28/properties {"name":"Veronica", "age":17, "hobbies":["shopping", "boys"]}

Not that a property value cannot be null or a JSON object. These two commands will fail:

PUT http://localhost:7474/db/data/node/28/properties {"name":"Veronica", "age":17, "hobbies":null}
PUT http://localhost:7474/db/data/node/28/properties {"name":"Veronica", "age":17, "hobbies":{"primary":"shopping", "secondary":"boys"}}

But these will work:

PUT http://localhost:7474/db/data/node/28/properties {"name":"Veronica", "age":17, "hobbies":""}

"" is an empty string, but it is not null.

PUT http://localhost:7474/db/data/node/28/properties {"name":"Veronica", "age":17, "hobbies":"{\"primary\":\"shopping\", \"secondary\":\"boys\"}"}

This time the hobbies JSON objects has been stringified, making it a valid Neo4j property value.

It would have been good to be able to use JSON as a property value too, but as of this writing we cannot have JSON objects as values of properties. The only valid data types for property values are numbers (integers and floats), strings, and arrays.

To update properties of a node

Editing an existing property involves the setting of the property with a new value.

PUT http://localhost:7474/db/data/node/29/properties/name "Archibald"
==> 204 No Content

Confirm the edit:

GET http://localhost:7474/db/data/node/29/properties/
==> 200 OK
==> {
==> "age" : 17,
==> "name" : "Archibald"
==> }

Note how we quoted "Archibald". Any string parameter needs to be quoted, numbers need not be.

Existing properties can also be updated using another method:

PUT http://localhost:7474/db/data/node/29/properties {"name":"Archie"}
GET http://localhost:7474/db/data/node/29/properties/
==> 200 OK
==> {
==> "name" : "Archie"
==> }

We have lost the age property! This method assumes that the accompanying JSON data is the new set of properties for the node. Since we excluded the age property, we lost it. For updating individual properties, use the first method.

To delete properties of a node

To delete a specific property:

DELETE http://localhost:7474/db/data/node/28/properties/hobbies

To delete the whole set of properties for a node:

DELETE http://localhost:7474/db/data/node/28/properties

Even though the examples were for nodes, the commands and parameters apply to working with relationship properties too. For example to add a property to a relationship:

PUT http://localhost:7474/db/data/relationship/10/properties/year 1941

The above will add a property called year with the value 1941 to the relationship id 10.

To list nodes

To get all the relationship types

GET http://localhost:7474/db/data/relationship/types
==> 200 OK
==> ["KNOWS","RELATED_TO","HATES","Hates","LOVES"]

Note that relationship types are case-insentitive, and persists forever, meaning once you create a relationship type, you can't delete it. That sounds strange, but that's the way it is as of this writing.

To get a better understanding of the relationships API and examples, let's create a graph of the students' relationship dynamics at a high school. Assume we have created seven nodes in a fresh new Neo4j database, let's add properties to those nodes:

PUT http://localhost:7474/db/data/node/1/properties {"name":"Archie"}
PUT http://localhost:7474/db/data/node/2/properties {"name":"Betty"}
PUT http://localhost:7474/db/data/node/3/properties {"name":"Veronica"}
PUT http://localhost:7474/db/data/node/4/properties {"name":"Jughead"}
PUT http://localhost:7474/db/data/node/5/properties {"name":"Reggie"}
PUT http://localhost:7474/db/data/node/6/properties {"name":"Ethel"}
PUT http://localhost:7474/db/data/node/7/properties {"name":"Food"}

To create a relationship

To create a relationship we make a POST request to a node's relationship path with a JSON data containing two mandatory properties "to" and "type".

For example, let's create a relationship from node 1 to node 2, with the relationship type (label) of "LOVES".

POST http://localhost:7474/db/data/node/1/relationships {"to" : "http://localhost:7474/db/data/node/2", "type" : "LOVES"}
==> 201 Created
==> {
==> "start" : "http://localhost:7474/db/data/node/1",
==> "data" : {
==> },
==> "self" : "http://localhost:7474/db/data/relationship/3",
==> "property" : "http://localhost:7474/db/data/relationship/3/properties/{key}",
==> "properties" : "http://localhost:7474/db/data/relationship/3/properties",
==> "type" : "LOVES",
==> "extensions" : {
==> },
==> "end" : "http://localhost:7474/db/data/node/2"
==> }

An id of 3 is assigned to the relationship we just created.

Similarly, let's create the rest of the high school relationship dynamics:

POST http://localhost:7474/db/data/node/1/relationships {"to" : "http://localhost:7474/db/data/node/3", "type" : "LOVES"}
POST http://localhost:7474/db/data/node/2/relationships {"to" : "http://localhost:7474/db/data/node/1", "type" : "LOVES"}
POST http://localhost:7474/db/data/node/3/relationships {"to" : "http://localhost:7474/db/data/node/1", "type" : "LOVES"}
POST http://localhost:7474/db/data/node/3/relationships {"to" : "http://localhost:7474/db/data/node/5", "type" : "LOVES"}
POST http://localhost:7474/db/data/node/4/relationships {"to" : "http://localhost:7474/db/data/node/7", "type" : "LOVES"}
POST http://localhost:7474/db/data/node/5/relationships {"to" : "http://localhost:7474/db/data/node/3", "type" : "LOVES"}
POST http://localhost:7474/db/data/node/6/relationships {"to" : "http://localhost:7474/db/data/node/4", "type" : "LOVES"}
POST http://localhost:7474/db/data/node/1/relationships {"to" : "http://localhost:7474/db/data/node/4", "type" : "FRIENDS"}
POST http://localhost:7474/db/data/node/4/relationships {"to" : "http://localhost:7474/db/data/node/1", "type" : "FRIENDS"}
POST http://localhost:7474/db/data/node/2/relationships {"to" : "http://localhost:7474/db/data/node/3", "type" : "FRIENDS"}
POST http://localhost:7474/db/data/node/3/relationships {"to" : "http://localhost:7474/db/data/node/2", "type" : "FRIENDS"}

Note that relationships are not "unique". By that I mean, if you were to run this command again:

POST http://localhost:7474/db/data/node/1/relationships {"to" : "http://localhost:7474/db/data/node/2", "type" : "LOVES"}

another relationship will be created with the same "to" and "type" value; you can create unlimited "duplicates", so be careful. I am not sure if this is a good feature or not, but that's the way Neo4j works at the moment.

To get the details of a relationship

For the details of a relationship, make a GET request to the relationship's path:

GET http://localhost:7474/db/data/relationship/3
==> 200 OK
==> {
==> "start" : "http://localhost:7474/db/data/node/1",
==> "data" : {
==> "intensity" : "low",
==> "since" : "day one"
==> },
==> "self" : "http://localhost:7474/db/data/relationship/3",
==> "property" : "http://localhost:7474/db/data/relationship/3/properties/{key}",
==> "properties" : "http://localhost:7474/db/data/relationship/3/properties",
==> "type" : "LOVES",
==> "extensions" : {
==> },
==> "end" : "http://localhost:7474/db/data/node/2"
==> }

To add properties to a relationship

Relationships, like nodes, can have properties too. Here is how you add a property to a relationship:

PUT http://localhost:7474/db/data/relationship/3/properties/intensity "low"

If you want to add multiple properties:

PUT http://localhost:7474/db/data/relationship/3/properties {"intensity":"low", "since":"day one"}

You can test the results of the two commands above this way:

GET http://localhost:7474/db/data/relationship/3

To create a relationship with properties

Relationship properties need not be added after creating the relationship, they can be added as the relationship is being created. Here is an example:

POST http://localhost:7474/db/data/node/1/relationships {"to" : "http://localhost:7474/db/data/node/5", "type" : "RIVALS", "data":{"intensity":"hight", "since":"day one"}}

Creating, reading, updating, and deleting relationship properties is similar to node properties, refer to the operations on node properties in the last examples.

To delete a relationship

Deleting a relationship is easy. Just call the DELETE command on the relationship path. For example:

DELETE http://localhost:7474/db/data/relationship/3

To see all the relationships on a node

GET http://localhost:7474/db/data/node/1/relationships/all

To see all the incoming relationships to a node

GET http://localhost:7474/db/data/node/3/relationships/in

To see all the outgoing relationships from a node

GET http://localhost:7474/db/data/node/4/relationships/out

To see typed relationships

Add the relationship type at the end of all or in or out query to filter the result accordingly. Look at these examples:

GET http://localhost:7474/db/data/node/1/relationships/all/LOVES
GET http://localhost:7474/db/data/node/4/relationships/out/LOVES
GET http://localhost:7474/db/data/node/4/relationships/in/LOVES

You can specify more than one relationship type:

GET http://localhost:7474/db/data/node/4/relationships/out/LOVES&FRIENDS

Important: make sure to escape the "&" character if making a direct call to the URL, else it will be interpreted as something else. If you are using an open source Neo4j REST client, probably the "&" issue may be taken care by the wrapper and it may not even be obvious to you.

Epilogue

In the above examples we have seen how nodes, relationships, and properties can be created, edited, updated, and deleted from the Neo4j HTTP terminal. But the question still remains "How do I actually use the REST API in Java, JavaScript, Node.js, Pythoh, Rails, PHP, .NET etc?".

Since the REST API is just HTTP request, all you have to do is make the appropriate HTTP request with the required data. That is relatively easy, but it is actually even easier because well written open source libraries are already there for most popular development platforms. Find them at http://docs.neo4j.org/chunked/snapshot/tutorials-rest.html.

While there is a REST client for both Java and Python, you might also want to check out Neo4j embedded for Java and Python.

Even though I'd like to cover the whole REST API in this tutorial, I will have to stop here for the sake reading comfort and content organization. There are other advanced topics under the REST API, namely: Indexes, Cypher Queries, Built-in Algorithms, and Batch Operations. If I were to include everything here, I might as well write a whole book on the REST API. I will be covering those topics in the coming days, in the mean time you can refer the official REST API docs at http://docs.neo4j.org/chunked/milestone/rest-api.html.

4 Responses to “Neo4j Tutorial – REST API”

  1. chris says:

    Brilliant tutorial! Better than the official docs

  2. Captain says:

    Thanks, Chris. In fact, I wrote this because the official docs gave me a headache.

  3. Bas says:

    Very good! Indeed better than the original. But from an application builder standpoint: How do you get the age of Archibald or he gets a “relationship” with Fiona? I won’t seem to figure that one out. It can not be that you need to keep an extra key:value database to know what node id you need to get a node by the name. Or am I missing the point here?

  4. evan says:

    beautifully written, makes a lot of sense.
    I actually didn’t know what REST is but having read this I was able to fiddle with it using Postman plugin in chrome, that really drove home the point that REST lets anyone to talk to your DB as if ur DB is a server or some sort that can handle http requests.
    all in all thanks so so much for this. The official docs were making my head spin and I was reading embedded java and getting so lost.

Make a Comment