Plugins provide an easy way to extend the Neo4j REST API with new functionality, without the need to invent your own API. Think of plugins as server-side scripts that can add functions for retrieving and manipulating nodes, relationships, paths, properties or indices.
Tip | |
---|---|
If you want to have full control over your API, and are willing to put in the effort, and understand the risks, then Neo4j server also provides hooks for unmanaged extensions based on JAX-RS. |
The needed classes reside in the org.neo4j:server-api jar file.
See the linked page for downloads and instructions on how to include it using dependency management.
For Maven projects, add the Server API dependencies in your pom.xml
like this:
<dependency> <groupId>org.neo4j</groupId> <artifactId>server-api</artifactId> <version>${neo4j-version}</version> </dependency>
Where ${neo4j-version} is the intended version.
To create a plugin, your code must inherit from the ServerPlugin class. Your plugin should also:
@PluginTarget
and the @Source
parameter are of the same type.
An example of a plugin which augments the database (as opposed to nodes or relationships) follows:
Get all nodes or relationships plugin.
@Description( "An extension to the Neo4j Server for getting all nodes or relationships" ) public class GetAll extends ServerPlugin { @Name( "get_all_nodes" ) @Description( "Get all nodes from the Neo4j graph database" ) @PluginTarget( GraphDatabaseService.class ) public Iterable<Node> getAllNodes( @Source GraphDatabaseService graphDb ) { return GlobalGraphOperations.at( graphDb ).getAllNodes(); } @Description( "Get all relationships from the Neo4j graph database" ) @PluginTarget( GraphDatabaseService.class ) public Iterable<Relationship> getAllRelationships( @Source GraphDatabaseService graphDb ) { return GlobalGraphOperations.at( graphDb ).getAllRelationships(); } }
The full source code is found here: GetAll.java
Find the shortest path between two nodes plugin.
public class ShortestPath extends ServerPlugin { @Description( "Find the shortest path between two nodes." ) @PluginTarget( Node.class ) public Iterable<Path> shortestPath( @Source Node source, @Description( "The node to find the shortest path to." ) @Parameter( name = "target" ) Node target, @Description( "The relationship types to follow when searching for the shortest path(s). " + "Order is insignificant, if omitted all types are followed." ) @Parameter( name = "types", optional = true ) String[] types, @Description( "The maximum path length to search for, default value (if omitted) is 4." ) @Parameter( name = "depth", optional = true ) Integer depth ) { Expander expander; if ( types == null ) { expander = Traversal.expanderForAllTypes(); } else { expander = Traversal.emptyExpander(); for ( int i = 0; i < types.length; i++ ) { expander = expander.add( DynamicRelationshipType.withName( types[i] ) ); } } PathFinder<Path> shortestPath = GraphAlgoFactory.shortestPath( expander, depth == null ? 4 : depth.intValue() ); return shortestPath.findAllPaths( source, target ); } }
The full source code is found here: ShortestPath.java
To deploy the code, simply compile it into a .jar file and place it onto the server classpath (which by convention is the plugins directory under the Neo4j server home directory).
Tip | |
---|---|
Make sure the directories listings are retained in the jarfile by either building with default Maven, or with |
The .jar file must include the file META-INF/services/org.neo4j.server.plugins.ServerPlugin with the fully qualified name of the implementation class. This is an example with multiple entries, each on a separate line:
org.neo4j.examples.server.plugins.GetAll org.neo4j.examples.server.plugins.DepthTwo org.neo4j.examples.server.plugins.ShortestPath
The code above makes an extension visible in the database representation (via the @PluginTarget
annotation)
whenever it is served from the Neo4j Server.
Simply changing the @PluginTarget
parameter to Node.class
or Relationship.class
allows us to target those parts of the data model should we wish.
The functionality extensions provided by the plugin are automatically advertised in representations on the wire.
For example, clients can discover the extension implemented by the above plugin easily by examining the representations
they receive as responses from the server, e.g. by performing a GET
on the default database URI:
curl -v http://localhost:7474/db/data/
The response to the GET
request will contain (by default) a JSON container that itself contains a container
called "extensions" where the available plugins are listed.
In the following case, we only have the GetAll
plugin registered with the server, so only its extension functionality is available.
Extension names will be automatically assigned, based on method names, if not specifically specified using the @Name
annotation.
{ "extensions-info" : "http://localhost:7474/db/data/ext", "node" : "http://localhost:7474/db/data/node", "node_index" : "http://localhost:7474/db/data/index/node", "relationship_index" : "http://localhost:7474/db/data/index/relationship", "reference_node" : "http://localhost:7474/db/data/node/0", "extensions_info" : "http://localhost:7474/db/data/ext", "extensions" : { "GetAll" : { "get_all_nodes" : "http://localhost:7474/db/data/ext/GetAll/graphdb/get_all_nodes", "get_all_relationships" : "http://localhost:7474/db/data/ext/GetAll/graphdb/getAllRelationships" } }
Performing a GET
on one of the two extension URIs gives back the meta information about the service:
curl http://localhost:7474/db/data/ext/GetAll/graphdb/get_all_nodes
{ "extends" : "graphdb", "description" : "Get all nodes from the Neo4j graph database", "name" : "get_all_nodes", "parameters" : [ ] }
To use it, just POST
to this URL, with parameters as specified in the description and encoded as JSON data content.
F.ex for calling the shortest path
extension (URI gotten from a GET
to http://localhost:7474/db/data/node/123):
curl -X POST http://localhost:7474/db/data/ext/GetAll/node/123/shortestPath \ -H "Content-Type: application/json" \ -d '{"target":"http://localhost:7474/db/data/node/456&depth=5"}'
If everything is OK a response code 200
and a list of zero or more items will be returned.
If nothing is returned (null returned from extension) an empty result and response code 204
will be returned.
If the extension throws an exception response code 500
and a detailed error message is returned.
Extensions that do any kind of write operation will have to manage their own transactions, i.e. transactions aren’t managed automatically.
Through this model, any plugin can naturally fit into the general hypermedia scheme that Neo4j espouses - meaning that clients can still take advantage of abstractions like Nodes, Relationships and Paths with a straightforward upgrade path as servers are enriched with plugins (old clients don’t break).
Copyright © 2012 Neo Technology