dmitriid/neo4j-erlang
{ "createdAt": "2013-12-22T18:44:41Z", "defaultBranch": "master", "description": "Erlang client library for Neo4J's REST API", "fullName": "dmitriid/neo4j-erlang", "homepage": null, "language": "Erlang", "name": "neo4j-erlang", "pushedAt": "2016-08-02T08:49:08Z", "stargazersCount": 38, "topics": [], "updatedAt": "2025-07-27T22:14:06Z", "url": "https://github.com/dmitriid/neo4j-erlang"}Erlang client library for Neo4J
Section titled “Erlang client library for Neo4J”This is a lightweight wrapper for Neo4j REST API.
Current versions: 0.2.1 and 0.3
Section titled “Current versions: 0.2.1 and 0.3”If you want to use Basic Auth, use v0.3. Otherwise use 0.2.1. Read on for more info.
Thanks to work by @dethtron5000, neo4j-erlang now supports Basic Auth. This means:
- The overall API is not changed
- There are breaking changes in the way you work with the API.
Changes
All API calls now require an additional parameter that contains request options. The options may contain the following parameters for Basic Auth:
{user, binary()}{password, binary}
Sample session for v0.3 (read below for v0.2.1)
### Sample session
```erlang
Options = [ {base_uri, <<"http://localhost:7474/db/data/">>} , {user, <<"user">>} , {password, <<"password">>} ],
Neo = neo4j:connect(Options),
StartNode = neo4j:get_node(Neo, 101, Options),EndNode = neo4j:create_node(Neo, {[{<<"prop1">>, <<"key1">>}]}, Options),
Relationship1 = neo4j:create_relationship(StartNode, EndNode, <<"KNOWS">>, Options),Relationship2 = neo4j:create_relationship(StartNode, EndNode, <<"KNOWS">>, {[{<<"prop2">>, <<"value2">>}]}, Options),
ok = neo4j:delete_relationship(Relationship1, Options).Except for the new required parameter the rest of this documentation remains unchanged for v0.3.
v0.2.1
Section titled “v0.2.1”All the information below is unchanged for version 0.2.1.
Thanks to:
- @sdebnath and @zsoci for Diyalizing
- @ppikula for fixing Hackney
- @msmilom for adding rebar configuration
Breaking changes from 0.1
- jsx has been replaced by jiffy. This means that you now absolutely have to use EEP0018 (refer to jiffy documentation for a more concise description. This readme and all comments throughout the code have been updated to reflect this change.
- Implements all of Neo4J 2.0.0’s REST API as referenced here with one caveat:
- Does not implement streaming API
- Uses jiffy for JSON
- Uses hackney for http queries
- Does not support HTTPS (yet?)
Sample session
Section titled “Sample session”Neo = neo4j:connect([{base_uri, <<"http://localhost:7474/db/data/">>}]),
StartNode = neo4j:get_node(Neo, 101),EndNode = neo4j:create_node(Neo, {[{<<"prop1">>, <<"key1">>}]}),
Relationship1 = neo4j:create_relationship(StartNode, EndNode, <<"KNOWS">>),Relationship2 = neo4j:create_relationship(StartNode, EndNode, <<"KNOWS">>, {[{<<"prop2">>, <<"value2">>}]}),
ok = neo4j:delete_relationship(Relationship1).Read on for more details, or refer to comments in [code]!(blob/master/src/neo4j.erl) or to the [test suite]!(blob/master/test/neo4j_SUITE.erl).
Details
Section titled “Details”The wrapper follows Neo4j’s REST API as close as possible. See code comments for direct links to each method/feature implemented. For example:
%%%% http://docs.neo4j.org/chunked/stable/rest-api-nodes.html#rest-api-create-node-with-properties%%-spec create_node(neo4j_root(), proplists:proplist()) -> neo4j_node() | {error, term()}.create_node(Neo, Props) -> {_, URI} = find(<<"node">>, 1, Neo), Payload = jiffy:encode(Props), create(URI, Payload).That link will tell you exactly what’s going on and what you should expect.
Errors
Section titled “Errors”There are two types of errors the wrapper returns:
{error, atom()}— some generic errors like{error, not_found}(which you can use for paged traversals):
> neo4j:get_node(Neo, 10000).{error,not_found}{error, {Status::integer(), URI::binary(), Error::proplists:proplist()}— errors returned by Neo4j. Example of such an error (using unique indexing):
> neo4j:unique_create_node(Neo, [{<<"prop">>, <<"val">>}], <<"index">>, <<"key">>, <<"value">>, <<"create_or_fail">>).[{<<"self">>, <<"http://localhost:7474/db/data/index/node/index/key/value/191">>}, {<<"extensions">>,[]}, {<<"paged_traverse">>, <<"http://localhost:7474/db/data/node/191/paged/traverse/{returnType}{?pageSize,leaseTime}">>}, {<<"labels">>,...
> neo4j:unique_create_node(Neo, [{<<"prop">>, <<"val">>}], <<"index">>, <<"key">>, <<"value">>, <<"create_or_fail">>).
error,{409, <<"http://localhost:7474/db/data/index/node/index?uniqueness=create_or_fail">>, [{<<"extensions">>,[]}, {<<"paged_traverse">>,...As expected, Neo4j returned a HTTP 409 Conflict code.
Assumptions
Section titled “Assumptions”Location header
Section titled “Location header”If an operation returns a HTTP 201 Created with a Location header, the wrapper will prepend a {<<"self">>, Location} to the proplist returned. Be wary of this especially when using paged traversals.
> Node = neo4j:get_node(Neo, 101).> Body = {[ {<<"order">>, <<"breadth_first">>} , {<<"uniqueness">>, <<"none">>} , {<<"return_filter">>, {[ {<<"language">>, <<"builtin">>} , {<<"name">>, <<"all">>} ]} } ]}.> PT = neo4j:paged_traverse(Node, Body).[ %% <<"self">> is prepended {<<"self">>, <<"http://localhost:7474/db/data/node/101/paged/traverse/node/2e23bfca61144b0f91b446fb6be562b6">>}, %% actual data {[{<<"labels">>, ...No JSON, just EEP0018 structures
Section titled “No JSON, just EEP0018 structures”Even for complex queries (such as Cypher queries or transactions) you never send in raw JSON, only proplists representing your objects:
See the example in “Binaries” below
Binaries
Section titled “Binaries”All string data and all URL parameters sent to Neo4J are assumed to be binaries.
As an example, let’s create a paged traverser
Neo = neo4j:connect([{base_uri, BaseUri}]),Node = neo4j:get_node(Neo, 101),Body = {[ {<<"order">>, <<"breadth_first">>} , {<<"uniqueness">>, <<"none">>} , {<<"return_filter">>, {[ {<<"language">>, <<"builtin">>} , {<<"name">>, <<"all">>} ]} } ]},PT = neo4j:paged_traverse(Node, Body, [ {<<"returnType">>, ReturnType} , {<<"leaseTime">>, LeaseTime} , {<<"pageSize">>, PageSize} ]).Does not do stuff for you
Section titled “Does not do stuff for you”- Will not urlencode your parameters (as required here). You’ll have to do it manually
- Will not assume that an integer/url references a valid node/relationship. You’ll have to retrieve nodes/relationships yourself. Typical workflow looks something like this:
Neo = neo4j:connect([{base_uri, <<"http://localhost:7474/db/data/">>}]),
%% will not work:neo4j:get_node_properties(101).
%% will not work:neo4j:get_node_properties(<<"http://localhost:7474/db/data/node/101">>).
%% correct way:Node = neo4j:get_node(N, 101),neo4j:get_node_properties(Node).
%% also correct:Node2 = neo4j:get_node(N, <<"http://localhost:7474/db/data/node/101">>),neo4j:get_node_properties(Node2).Contributing
Section titled “Contributing”Yes, please! :) If you have ideas, suggestions, pull requests or issues, do not hesitate to send them my way