Skip to content

App Developers: Cytoscape Command Best Practices

dotasek edited this page Oct 24, 2017 · 27 revisions

When developing apps that enable automation, observing best practices in coding and design can greatly improve the accessibility of that automation, its interaction with other apps and services, and aid in tracing any errors during testing and in runtime.

This page documents best practices for app developers who are enabling automation features as Cytoscape Commands, and assumes some familiarity with adding commands.

To determine whether you should expose automation features as Commands, Functions or both, consult the automation summary page.

For best practices relating to Cytoscape Functions, see Cytoscape Function Best Practices for and Swagger Best Practices.

Command Namespaces

The namespace you choose for your command via the ServiceProperties.COMMAND_NAMESPACE property should succinctly and uniquely describe its place among all other commands. For example, all layout commands are registered with the layout namespace.

Tunables and the Cytoscape GUI

When creating a task that contains Tunables, it is important to be aware of the context field in the Tunable annotation.

@Tunable (description="Example Input Parameter", context=Tunable.BOTH_CONTEXT)

The above code snippet specifies that the Tunable field is intended for inclusion in both the Cytoscape GUI and in the Cytoscape Command Line. Options exist for Tunables that are in the GUI only (Tunable.GUI_CONTEXT) and non-GUI (Tunable.NOGUI_CONTEXT). It is important that no Tunables required for the execution of the Task via automation are of the Tunable.GUI_CONTEXT type.

Documentation

Several fields and parameters exist to provide users with documentation about Commands. This documentation becomes available in both the Command Line, accessible through via Tools --> Command Line Dialog in the Cytoscape menu bar, and in the CyREST Command API Swagger, accessible through via Help --> Automation --> CyREST Command API in the Cytoscape menu bar.

Command Description

The ServiceProperties.COMMAND_DESCRIPTION property is set when a service is registered, and can be seen in the code snippet below:

String returnAValueDescription = "Add two numbers (a and b) and return their value using ObservableTask.";
		
Properties returnAValueTaskFactoryProperties = new Properties();

...

returnAValueTaskFactoryProperties.setProperty(COMMAND_DESCRIPTION,  returnAValueDescription);

...

TaskFactory returnAValueTaskFactory = new ReturnAValueTaskFactory();
registerAllServices(bc, returnAValueTaskFactory, returnAValueTaskFactoryProperties);

The command description can then be seen in two locations: the Command Line Dialog and the Swagger UI.

Command Line Dialog Command Description

Swagger UI Command Description

Since the space allotted to this description is limited in both cases, any text in a description should be kept informative, but brief.

Tunable Description

The Tunable description field can be set for any Tunable annotation to provide a brief description. An example implementation can be seen in the code snippet below:

@Tunable (description="Value A")
public Double a = 0.1;

Tunable descriptions can then be seen in two documentation locations: the Command Line Dialog and the Swagger UI.

Command Line Dialog Tunable Descriptions

Swagger UI Tunable Descriptions

Since the space allotted to this description is limited in both cases, any text in a description should be kept informative, but brief.

Additionally, if the context of the Tunable is BOTH, the description will appear in the dialog for the relevant Command.

Cytoscape Dialog Tunable Descriptions

The appearance of the description in Cytoscape dialogs, Command Line Help, and Swagger UI should always be considered when writing descriptions, and should be easily understandable in every context.

JSON Capable Commands

These features are only available in Cytoscape 3.6 and up, and use the CyREST develop branch. See the TaskFactory JSON Result Sample for details on these dependencies

As of Cytoscape 3.6, Commands are capable of providing JSON results via CyREST. Using JSON allows complex data to be made available outside of Cytoscape via Commands, and their use enables richer documentation through Swagger. Implementing JSON output is highly recommended for every command.

The TaskFactory JSON Result Sample provides an example of how to implement JSON Results for a Command.

CIResponse

When a JSON Command is executed, the JSON Results for each Task in that Command are included as a list in the data field of a CIResponse JSON object. The results of a simple query to a JSON Command are shown below:

{
  "data": {
    "results": [
      {
        "name": "Hodor",
        "values": [
          1,
          2,
          3
        ]
      }
    ]
  },
  "errors": []
}

Details about the CIResponse model can be found in the CIResponse Section of the Cytoscape Function Best Practices wiki page.

Reporting Errors in JSON Command Execution

If a Task throws an Exception, that exception will be translated into a CIError, which will be included in the errors field of a CIResponse. An example of a thrown error within a CIResponse is shown below:

{
  "data": {
    "results": []
  },
  "errors": [
    {
      "status": 500,
      "type": "urn:cytoscape:ci:cyrest-core:v1:handle-json-command:errors:2",
      "message": "Error processing arguments: Couldn't parse value from: string for setting: taxonID",
      "link": "file:/Users/davidotasek/CytoscapeConfiguration/3/framework-cytoscape.log"
    }
  ]
}

The message field of the CIError is generated from the message field of the Java Exception thrown. To make common errors easier for automation scripters to handle, errors thrown from Tasks should be built using concise and specific messages describing the error.

Details about the enclosing CIError model can be found in the CIError Section of the Cytoscape Function Best Practices wiki page.

Recommended JSON Practices

When deciding on the representation of data in JSON, care should be taken to ensure that the representation conforms to pre-existing Cytoscape conventions and that the JSON returned satisfies the needs of the command's caller while containing no unnecessary information.

The Standard Cytoscape JSON Models wiki page contains a list of standard JSON representations used within Cytoscape. The Cytoscape JSON Utilities Sample contains a reference implementation of how to produce these using utilities within Cytoscape. Before implementing any JSON to represent Cytoscape objects, check to see what established standards exist.

As a general practice, JSON representations should contain references instead representations of an entire object where possible. For example, nodes, edges, networks, and many other Cytoscape objects can be referenced by their SUID, a unique long number. Such a representation can be seen below:

{ "SUID":63 }

This reference is enough to call other commands to get a much more comprehensive representation of the object it represents:

{
  "data": {
    "id": 63,
    "SUID": 63,
    "shared name": "Node 1",
    "name": "Node 1",
    "selected": false,
    "int_column": 1
  }
}

Sending all of the latter information is unnecessary in most cases, and should only be used when specific details are needed. Keeping the size of JSON returns to a minimum ensures that scripts can run a command faster, with less transfer of data per execution, and more easily comprehensible results.

Command Long Description

The ServiceProperties.COMMAND_LONG_DESCRIPTION property is set when a service is registered, and can be seen in the code snippet below:

public void start(BundleContext bc) throws InvalidSyntaxException 
{  
   ...
   String returnAValueLongDescription = "Returns a JSON Object containing a ```name``` and a ```values``` field. The ```name``` field is set by the request message body. The ```values``` field is preset.";
   ...		
   returnAValueTaskFactoryProperties.setProperty(COMMAND_LONG_DESCRIPTION, returnAValueLongDescription);
   ...
   TaskFactory returnAValueTaskFactory = new ReturnJSONTaskFactory();
   registerAllServices(bc, returnAValueTaskFactory, returnAValueTaskFactoryProperties);
   ...
}

The command long description can then be seen in the Implementation Notes section of the Swagger UI.

Swagger UI Command Long Description

The space allotted to a long description is large, and the description text supports the use of Markdown, which can be used for styling, making links, and providing formatted code examples. Including clear and explicit instructions using the long description is strongly advised.

Command Example JSON

The ServiceProperties.COMMAND_EXAMPLE_JSON property is set when a service is registered, and can be seen in the code snippet below:

public static final String getExample() {
   return ReturnJSONTask.getJson(new SampleResult("Hodor", Arrays.asList(1, 2, 3)));
}

...
  	
public void start(BundleContext bc) throws InvalidSyntaxException 
{
   ...
   returnAValueTaskFactoryProperties.setProperty(COMMAND_EXAMPLE_JSON, getExample());
   ...
   TaskFactory returnAValueTaskFactory = new ReturnJSONTaskFactory();
   registerAllServices(bc, returnAValueTaskFactory, returnAValueTaskFactoryProperties);
   ...
}

The generated example JSON can then be seen in the Example Value section of the Swagger UI.

Swagger UI Command Example JSON

This provides users with an example of data that can be returned by the command. Care should be taken to ensure that the example data matches the output the command generates. In our example, we ensured this by using the Task's own methods to generate the example json.

Tunable Long Description

The Tunable long description field can be set for any Tunable annotation to provide a more detailed description. An example implementation can be seen in the code snippet below:

@Tunable (..., longDescription="The value to return in the result's ```name``` field", ...)
	public String name = "";

Tunable descriptions can then be seen in Data Type section in the Swagger UI.

Swagger UI Tunable Long Descriptions

Long description text supports the use of Markdown, which can be used for styling, making links, and providing formatted code examples. Including clear and explicit instructions using the long description is strongly advised.

Tunable Example String Value

The Tunable example string value field can be set for any Tunable annotation to provide an example of a string that a Tunable value can be expected to be set to. An example implementation can be seen in the code snippet below:

@Tunable (..., exampleStringValue="Mort")
	public String name = "";

Swagger UI Tunable Example String Values

Best Practices Checklist

After implementing a Command, it is advised to use the checklist below to evaluate if your command follows best practices in output and documentation.

Links in checklist headings will direct you to any relevant portions of the Best Practices document.

  • Does it differentiate each command from all the others in Cytoscape?
  • Do it clearly identify the purpose of the command?
  • Is it sufficiently brief? It should display without difficulty in the Swagger UI.
  • Does it guide a novice user through using the command?
  • Does it explain any necessary preconditions, multiple modes of execution, or parameter interdependencies?
  • Does it explain any conditions that can cause errors?
  • Is it displayed in the Swagger page (it won’t display if the JSON is invalid)
  • Is it representative of a reasonable output?
  • Does each tunable longDescription inform the novice user of its purpose?
  • Does each tunable longDescription describe its expected format?
  • If a tunable has any specific values (such as ‘all’, ‘selected’, etc.), are these listed and described?
  • Does each tunable have an exampleStringValue?
  • Is each tunable exampleStringValue representative of a reasonable input?
  • Does each tunable explain any conditions that can cause errors?
  • Does your command produce valid JSON?
  • Does your command use CyJSONUtil to produce JSON for any Cytoscape models?
  • Does your command use references where possible to maintain efficient output?
Clone this wiki locally