Thursday, June 18, 2015

Neo4j and REST API from Java when authentication is required

Based on "The Neo4j v2.3.0-M01 Manual" manual under 7.1 How to use the REST API from Java, I've developed the same example program using Jersey library (2.19). The goal of this example is to use the REST API from Java when auth is required.

The Jersey Client API reuses many aspects of the JAX-RS and the Jersey implementation. To utilize the client API it is first necessary to build an instance of a Client using one of the static ClientBuilder factory methods. Once you have a Client instance you can create a WebTarget from it.


Client client = ClientBuilder.newClient();
WebTarget webTarget = client.target("http://example.com/rest/");

The uri passed to the method as a String is the URI of the targeted web resource that represents a context root of a RESTful application. If there is a resource exposed on the URI "http://example.com/rest/resource", a WebTarget instance can be used to derive other web targets.

WebTarget resourceWebTarget = webTarget.path("resource");

The resourceWebTarget now points to the resource on URI "http://example.com/rest/resource"

In our example program, once the server is started, we’ll check the connection to it.
 
Authentication would take place the following code snippet,
private static WebTarget testDatabaseAuthentication()
{
    // START SNIPPET: testAuthentication
    Client client = ClientBuilder.newClient();

    HttpAuthenticationFeature authFeature =
        HttpAuthenticationFeature.basic(username, password);
    
    client.register(authFeature);

    WebTarget target = client.target(SERVER_ROOT_URI);

    Response response = target
            .request()
            .header("application/xml", "true")
            .get();

    String entity = response.readEntity(String.class);

    System.out.println( String.format(
            "GET, status code [%d], returned data: "
                    + System.getProperty( "line.separator" ) + "%s",
            response.getStatus(), entity ) );

    response.close();
    return target;
    // END SNIPPET: testAuthentication
}

In order to enable http authentication support in Jersey client register the HttpAuthenticationFeature. For our example I’ve used basic pre-emptive authentication. I’ll keep the 'target' object along the whole program so I don’t to need to login in each of the different methods again.

The main method should look as follows,

private static final String SERVER_ROOT_URI = "http://localhost:7474/db/data/";

private static final String username = "neo4j_username";
private static final String password = "neo4j_password";

public static void main( String[] args ) //throws URISyntaxException
{
    WebTarget target = testDatabaseAuthentication();

    // START SNIPPET: nodesAndProps
    URI firstNode = createNode( target );
    addProperty( target, firstNode, "name", "Joe Strummer" );
    URI secondNode = createNode( target );
    addProperty( target, secondNode, "band", "The Clash" );
    // END SNIPPET: nodesAndProps

    // START SNIPPET: addRel
    URI relationshipUri = addRelationship( target, firstNode, secondNode, "singer",
    "{ \"from\" : \"1976\", \"until\" : \"1986\" }" );
    // END SNIPPET: addRel

    // START SNIPPET: addMetaToRel
    addMetadataToProperty( target, relationshipUri, "stars", "5" );
    // END SNIPPET: addMetaToRel

    // START SNIPPET: queryForSingers
    findSingersInBands( target, firstNode );
    // END SNIPPET: queryForSingers

    sendTransactionalCypherQuery( target, "MATCH (n) WHERE has(n.name) RETURN n.name AS name" );
}

If you want you can download the code from my GitHub

All the best,
José