REST API使用 HTTP协议传输,数据采用JSON格式,以至于他能被需要计算机语言和平台使用。尽管如此,准备开始使用之前,看一些可以重用的模式是非常有用的。在这 个简短的概述中,我们将为你展示如何通过REST API创建一个或者多个简单图并且查询他里面存在的数据。
为了得到这些范例,我们选择了 Jersey 客户端组件,他可以通过Maven轻松下载。
在我们准备在Neo4j服务端做任何操作之前,我们需要先启动他,可以参考:3.7.1. 数据库服务端安装。
WebResource resource = Client.create()
.resource( SERVER_ROOT_URI );
ClientResponse response = resource.get( ClientResponse.
class
);
System.out.println( String.format(
"GET on [%s], status code [%d]"
,
SERVER_ROOT_URI, response.getStatus() ) );
response.close();
|
如果返回的状态码是200 OK
, 那我们就确定 Neo4j 服务端已经成功运行,我们可以继续使用了。如果连接到服务端失败,请参考:3.7. Neo4j数据库服务端。
注意 |
如果你获得的返回码大于200 OK (特别是 4xx 或者 5xx ),那请您检查你的配置并查看在目录data/log中的日志。 |
REST API 使用 POST
来创建节点. 在Java中封装的接口使用Jersey客户端便可以非常容易使用:
final
String nodeEntryPointUri = SERVER_ROOT_URI +
"node"
;
WebResource resource = Client.create()
.resource( nodeEntryPointUri );
// POST {} to the node entry point URI
ClientResponse response = resource.accept( MediaType.APPLICATION_JSON )
.type( MediaType.APPLICATION_JSON )
.entity(
"{}"
)
.post( ClientResponse.
class
);
final
URI location = response.getLocation();
System.out.println( String.format(
"POST to [%s], status code [%d], location header [%s]"
,
nodeEntryPointUri, response.getStatus(), location.toString() ) );
response.close();
return
location;
|
如果调用成功完成,他会在后台发送一个包含JSON数据的HTTP请求给服务端。服务端会在数据库中创建一个新的节点并且返回状态码 201 Created
和访问这个新节点的地址
。
在我们的范例中,我们将调用这个功能两次以便在数据库中创建两个节点。
一旦我们在数据库中有了节点,我们可以使用他们来保存有用的数据。在这个范例中,我们将在我们的数据库中保存音乐信息。下面让我们浏览下面的代码, 代码中,我们创建了节点并且给节点增加属性。这里,我们新增一个节点“Joe Strummer”,并且增加了一个属性 “brand”,属性值是: “The Clash”。
URI firstNode = createNode();
addProperty( firstNode,
"name"
,
"Joe Strummer"
);
URI secondNode = createNode();
addProperty( secondNode,
"band"
,
"The Clash"
);
|
在方法addProperty
内部,我们确定了代表节点属性的名称,以及该属性的值。然后我们使用PUT
将该属性发送到服务端。
String propertyUri = nodeUri.toString() +
"/properties/"
+ propertyName;
// http://localhost:7474/db/data/node/{node_id}/properties/{property_name}
WebResource resource = Client.create()
.resource( propertyUri );
ClientResponse response = resource.accept( MediaType.APPLICATION_JSON )
.type( MediaType.APPLICATION_JSON )
.entity(
"\""
+ propertyValue +
"\""
)
.put( ClientResponse.
class
);
System.out.println( String.format(
"PUT to [%s], status code [%d]"
,
propertyUri, response.getStatus() ) );
response.close();
|
如果一切顺利,我们将会得到返回码:204 No Content
,表示服务端已经受理这个请求,整个请求不会回显属性的值。
现在我们有了表示Joe Strummer 和 The Clash的节点,我们可以关联他们。REST API通过一个POST
方式支持对节点建立关系。在Java中相应地,我们POST>
一些JSON到节点Joe Strummer的节点地址,确定了该节点和The Clash节点之间的关系。
URI relationshipUri = addRelationship( firstNode, secondNode,
"singer"
,
"{ \"from\" : \"1976\", \"until\" : \"1986\" }"
);
|
在addRelationship
方法中,我们确定了Joe Strummer节点的地址,然后POST
一些JSON数据从而建立关系。这些JSON数据包括目标节点,关系的类型以及一些关系的属性等。
private
static
URI addRelationship( URI startNode, URI endNode,
String relationshipType, String jsonAttributes )
throws
URISyntaxException
{
URI fromUri =
new
URI( startNode.toString() +
"/relationships"
);
String relationshipJson = generateJsonRelationship( endNode,
relationshipType, jsonAttributes );
WebResource resource = Client.create()
.resource( fromUri );
// POST JSON to the relationships URI
ClientResponse response = resource.accept( MediaType.APPLICATION_JSON )
.type( MediaType.APPLICATION_JSON )
.entity( relationshipJson )
.post( ClientResponse.
class
);
final
URI location = response.getLocation();
System.out.println( String.format(
"POST to [%s], status code [%d], location header [%s]"
,
fromUri, response.getStatus(), location.toString() ) );
response.close();
return
location;
}
|
如果一切正常,我们将得到返回码:201 Created
和一个地址Location
,这个地址是我们刚建立的关系的地址。
像节点一样,管东西一样拥有属性。自从我们大量关注Joe Strummer和 The Clash以来,我们增加了他们的关系的属性:等级,以至于我们可以看到一个五星级的品牌属性。
addMetadataToProperty( relationshipUri,
"stars"
,
"5"
);
|
在addMetadataToProperty
方法中,我们确定了关系的地址,然后PUT
我们新的值到服务端,这些新的值会覆盖过去已经存在的,所以请在操作之前务必谨慎。
private
static
void
addMetadataToProperty( URI relationshipUri,
String name, String value )
throws
URISyntaxException
{
URI propertyUri =
new
URI( relationshipUri.toString() +
"/properties"
);
String entity = toJsonNameValuePairCollection( name, value );
WebResource resource = Client.create()
.resource( propertyUri );
ClientResponse response = resource.accept( MediaType.APPLICATION_JSON )
.type( MediaType.APPLICATION_JSON )
.entity( entity )
.put( ClientResponse.
class
);
System.out.println( String.format(
"PUT [%s] to [%s], status code [%d]"
, entity, propertyUri,
response.getStatus() ) );
response.close();
}
|
假设一切正常,我们将得到返回码:200 OK
(我们也可以通过调用ClientResponse.getStatus()
来检查),到此,我们已经建立起了一个小型的图数据库网络,我们已经可以从中查询一些有价值的数据了。
跟图数据嵌入模式一样,Neo4j服务端模式也使用图遍历来查询数据。当前,Neo4j服务端希望得到一个JSON格式的查询请求通过POST
发送给他以便遍历数据库。(虽然这在以GET
方式传送的适合随时都会发生变化)。
为了启动这个查询,我们使用了一个能做JSON转换的类,准备POST
数据到服务端。在这种情况下,我们硬编码到遍历查询条件中,查找所有有类型是"singer"
的输出关系的节点。
// TraversalDescription turns into JSON to send to the Server
TraversalDescription t =
new
TraversalDescription();
t.setOrder( TraversalDescription.DEPTH_FIRST );
t.setUniqueness( TraversalDescription.NODE );
t.setMaxDepth(
10
);
t.setReturnFilter( TraversalDescription.ALL );
t.setRelationships(
new
Relationship(
"singer"
, Relationship.OUT ) );
|
一旦我们确定了遍历的参数,我们只需要转换它。我们确定了遍历的开始节点,然后POST
JSON数据到服务端开始查询。
URI traverserUri =
new
URI( startNode.toString() +
"/traverse/node"
);
WebResource resource = Client.create()
.resource( traverserUri );
String jsonTraverserPayload = t.toJson();
ClientResponse response = resource.accept( MediaType.APPLICATION_JSON )
.type( MediaType.APPLICATION_JSON )
.entity( jsonTraverserPayload )
.post( ClientResponse.
class
);
System.out.println( String.format(
"POST [%s] to [%s], status code [%d], returned data: "
+ System.getProperty(
"line.separator"
) +
"%s"
,
jsonTraverserPayload, traverserUri, response.getStatus(),
response.getEntity( String.
class
) ) );
response.close();
|
一旦这个请求完成,我们将得到我们的歌手的数据集以及他们属于的品牌:
[ {
"data"
: {
"band"
:
"The Clash"
,
"name"
:
"Joe Strummer"
},
"all_typed_relationships"
:
"http://localhost:7474/db/data/node/82/relationships/all/{-list|&|types}"
,
"outgoing_typed_relationships"
:
"http://localhost:7474/db/data/node/82/relationships/out/{-list|&|types}"
,
"incoming_typed_relationships"
:
"http://localhost:7474/db/data/node/82/relationships/in/{-list|&|types}"
,
}, {
"data"
: {
},
"all_typed_relationships"
:
"http://localhost:7474/db/data/node/83/relationships/all/{-list|&|types}"
,
"outgoing_typed_relationships"
:
"http://localhost:7474/db/data/node/83/relationships/out/{-list|&|types}"
,
"incoming_typed_relationships"
:
"http://localhost:7474/db/data/node/83/relationships/in/{-list|&|types}"
,
} ]
|
这就是我们使用REST API的方式。自然对于对HTTP协议不了解的,我们提供了对HTTP操作的封装,包括通过DELETE
移除节点和关系。当然,如果你想了解更多,你可以尝试在Jersey客户端代码中采用.post()
来代替.delete()
。
HTTP API 提供了大量客户端基本操作的实现,也包括HTTP和REST。在将来,虽然 REST API的方式占有一定的优势,但是我们还是期望出现语言级的方式来做客户端,能更轻松的绑定到Neo4j的嵌入模式(比如python)。关于当前 Neo4j REST客户端以及嵌入封装,请查看:http://www.delicious.com/neo4j/drivers。
http://www.neo4j.org.cn/2012/07/30/server-java-rest-client-example/#maodian001
http://docs.neo4j.org.cn/