Reputation: 311
I have a huge Neo4j database that I created using the batch import tool. Now I want to expose certain parts of the data via APIs (that will run a query in the backend) to my users. My requirements are pretty general:
1. Latency should be minimum
2. Support qps of about ~10-20.
Can someone give me recommendations on what I should use for this and any documentation on how to go about this? I see several examples of ruby/rails and REST APIs -- however they are specific to exposing the data as is without any complex queries in the backend. I am not sure how to translate that into the specific APIs that I want. Any help would be appreciated.
Thanks.
Upvotes: 1
Views: 1070
Reputation: 31
Use grest.
You can simply define your primary model(s) and its relation(s) (as secondary) and build an API with minimal coding and as quickly as possible!
Upvotes: 0
Reputation: 2661
Check out the GraphAware Framework. You can build the APIs directly on top of Neo4j (same JVM) but you have to use Cypher, Java, or Scala.
I'd start with Cypher, because you can write it very quickly, then optimise for performance, and finally, if all else fails and your latency is still to high, convert to Java.
You can expose subgraphs (or even partially hydrated nodes and relationship, i.e. only certain properties) very easily. Checkout out the stuff in the api
package. Example code:
You'd write a controller to return a person's graph, but only include nodes' names (not ages or anything else):
@RestController
public class ApiExample {
private final GraphDatabaseService database;
@Autowired
public ApiExample(GraphDatabaseService database) {
this.database = database;
}
@RequestMapping(path = "person/{name}")
public JsonGraph getPersonGraph(@PathVariable(value = "name") String name) {
JsonGraph<?> result = new JsonGraph() {
@Override
protected JsonGraph self() {
return this;
}
};
try (Transaction tx = database.beginTx()) {
Node person = database.findNode(label("Person"), "name", name);
if (person == null) {
throw new NotFoundException(); //eventually translate to 404
}
result.addNode(person, IncludeOnlyNameNodeTransformer.INSTANCE);
for (Relationship worksFor : person.getRelationships(withName("WORKS_FOR"), Direction.OUTGOING)) {
result.addRelationship(worksFor);
result.addNode(worksFor.getEndNode(), IncludeOnlyNameNodeTransformer.INSTANCE);
}
tx.success();
}
return result;
}
private static final class IncludeOnlyNameNodeTransformer implements NodeTransformer<LongIdJsonNode> {
private static final IncludeOnlyNameNodeTransformer INSTANCE = new IncludeOnlyNameNodeTransformer();
private IncludeOnlyNameNodeTransformer() {
}
@Override
public LongIdJsonNode transform(Node node) {
return new LongIdJsonNode(node, new String[]{"name"});
}
}
}
Running this test
public class ApiExampleTest extends GraphAwareApiTest {
@Override
protected void populateDatabase(GraphDatabaseService database) {
database.execute("CREATE INDEX ON :Person(name)");
database.execute("CREATE (:Person {name:'Michal', age:32})-[:WORKS_FOR {since:2013}]->(:Company {name:'GraphAware', est:2013})");
}
@Test
public void testExample() {
System.out.println(httpClient.get(baseUrl() + "/person/Michal/", 200));
}
}
would return the following JSON
{
"nodes": [
{
"properties": {
"name": "GraphAware"
},
"labels": [
"Company"
],
"id": 1
},
{
"properties": {
"name": "Michal"
},
"labels": [
"Person"
],
"id": 0
}
],
"relationships": [
{
"properties": {
"since": 2013
},
"type": "WORKS_FOR",
"id": 0,
"startNodeId": 0,
"endNodeId": 1
}
]
}
Upvotes: 1
Reputation: 8556
I wrote a simple Flask API example that interfaces with Neo4j for a simple demo (backend for a messaging iOS app).
You might find it a helpful reference: https://github.com/johnymontana/messages-api
There are also a few resources online for using Flask with Neo4j:
Upvotes: 2
Reputation: 10856
Obviously you can roll your own using frameworks like Rails / Sinatra. If you want a standard for the way that your API is formatted I quite like the JSON API standard:
Here is an episode of The Changelog podcast talking about it:
There's also a gem for creating resource objects which determine what is exposed and what is not:
https://github.com/cerebris/jsonapi-resources
I tried it out a bit with the neo4j
gem and it works at a basic level, though once you start getting into include
s there seems to be some dependencies on ActiveRecord. I'd love to see issues like that worked out, though.
You might also check out the GraphQL standard which was created by Facebook:
https://github.com/facebook/graphql
There's a Ruby gem for it:
https://github.com/rmosolgo/graphql-ruby
And, of course, another episode of The Changelog ;)
Various other API resources for Ruby:
https://github.com/webmachine/webmachine-ruby https://github.com/ruby-grape/grape
Upvotes: 1