-
Notifications
You must be signed in to change notification settings - Fork 58
Building CI Responses
This page describes how developers creating Cytoscape Automation Functions can generate valid CI Response data. The CI Response model is a data standard shared by multiple Cytoscape Cyber-infrastructure services, such as Diffusion and CyNDEx, and is described in greater detail in the Cytoscape Function Best Practices wiki page for App Developers.
There are a number of ways to build a CI Response from within an App. If you are adding Automation using Functions, you will have a great deal of flexibility in how to produce your data, from streaming, to automatic mapping via JAX-RS, to manual construction using strings. Familiarizing yourself with all these options will allow you to choose a method that requires less coding and is more appropriate to the automation function you are building.
The ci-api
Cytoscape models and utilities are very useful in creating CI Responses and errors, and are used throughout the following code. They remove boilerplate code and are reduce errors. They are provided in the Cytoscape API. To use these models, you can use the following code snippet in the dependencies section of your pom.xml
file:
<dependency>
<groupId>org.cytoscape</groupId>
<artifactId>ci-api</artifactId>
<version>3.6.0</version>
<scope>provided</scope>
</dependency>
The Diffusion App makes extensive use of these models and is a good example of their intended use.
Create a CIResponse
instance whose type variable T is a class containing the operation's return value. For example, to return a class called DiffusionResultColumns
containing the operation result, you should define the DiffusionResultColumns
class and return it:
public static class DiffusionAppResponse extends CIResponse<DiffusionResultColumns>{
}
...
DiffusionAppResponse myAppFunction(...) {
...
DiffusionAppResponse ci = new DiffusionAppResponse();
ci.data = new DiffusionResultColumns(...);
...
return ci;
}
The errors
field should remain unset.
If an operation returns a CIResponse<T>
class, CyREST will convert the class to JSON before returning the result to the caller.
While we recommend that an operation return a result as a CIResponse
class, it is equally acceptable to return it as a JSON string. This can be used in instances where a the app developer wishes to manually create JSON, through a library such as GSON, or Jackson, or by other means. An example of this process is shown in the code snippet below:
public static class MyAppResponse extends CIResponse<MyResponseModel>{
}
...
@ApiOperation(value = "My custom JSON Operation",
notes = "A prose description of what my JSON Operation Does",
response = MyAppResponse.class)
@Produces(MediaType.APPLICATION_JSON)
public String myAppFunction(...) {
...
String myJSONData;
...
// Build your JSON.
...
return "{ \"data\":{" + myJSONData + "}, \"errors\":[]}";
}
Note that we included an @APIOperation
annotation for myAppFunction
. This follows Swagger Best Practices by providing our Swagger documentation with MyAppResponse.class
, a class that provides the data model for myJSONData
. Without this annotation, there is no way for Swagger or any other documentation system to convey what myJSONData
could contain.
When an operation return result can grow large, we recommend that the operation return a streamed CIResponse instead of a CIResponse class or String. In such an instance, we can use a combination of JAX-RS's StreamingOutput
and Response
classes to produce a valid CIResponse
. An example of this process is shown in the code snippet below:
public static class MyAppResponse extends CIResponse<MyResponseModel>{
}
...
@ApiOperation(value = "My custom JSON Operation",
notes = "A prose description of what my JSON Operation Does",
response = MyAppResponse.class)
@Produces(MediaType.APPLICATION_JSON)
public Response myAppFunction() {
StreamingOutput stream = new StreamingOutput() {
@Override
public void write(OutputStream os) throws IOException,
WebApplicationException {
Writer writer = new BufferedWriter(new OutputStreamWriter(os));
writer.write("{ \"data\":{");
...
// Add your JSON
...
writer.write("}, \"errors\":[]}");
writer.flush();
}
};
return Response.ok(stream).build();
}
Note that we included an @APIOperation
annotation for myAppFunction
. See the previous example, Returning a CIResponse by manually building a response String for a detailed explanation of why this is done.