Introduction
This document explains what conventions and coding guidelines to follow when writing new API(s) for CloudStack or updating the existing ones.
References
Instructions
When you need to introduce a new API command to the CS, you will need to create a Request Class and a Response class (or re-use existing API Response class, if you are extending CS API functionality for which API response is already defined)
Writing CS API Request class
- Pick up the *Cmd abstract class to extend by the request.
CUD (create/update/delete commands):
![](/confluence/download/attachments/39622334/CUD.png?version=1&modificationDate=1394571104000&api=v2)
R (read-list) commands:
![](/confluence/download/attachments/39622334/R.png?version=1&modificationDate=1394571118000&api=v2)
IMPORTANT - starting 2.x, new CUD API command can no longer extend BaseCmd class; they should come as Async command, and extend either BaseAsyncCmd, or BaseAsyncCreateCmd.
When to extend BaseAsyncCmd vs BaseAsyncCreateCmd? Use BaseAsyncCreate for the commands creating a new CS entry. For UD commands extend BaseAsyncCmd.
2. Command class that you add, should end with *Cmd, and annotated with @ApiCommand. Read more about @ parameters in Annotations use in the API ref.
3. Define all request parameters. Annotate them all with @Parameter.
4. Implement execute() for RUD commands, and execute()/create() for C commands.
5. Add s_name - the response name. Should be specified in lower case.
6. When thinking about the command name, prepend it with create/delete/update/list depending on a context. Only if none of those prependers fit your logic, use your own (assign for example)
Writing CS API Response class
- Make your class extend BaseResponse
- Annotate the class with @EntityReference set with the CloudStack interface representing the object you are returning to the API user. For example, VolumeResponse has @EntityReference set with Volume.
- Annotate each parameter with @SerializedName and @Param annotations. See more details on these annotations in Annotations use in the API
- Parameter names should be lower case
- Make sure that you don't expose actual DB ids by setting them to your Ids fields. Use UUID value instead.
API placement and registration
Command placement depends on whether is command is coming as a part of plugin that can be enabled/disabled, or CloudStack core base.
When command comes as a part of CS core base
- Location: The request/response code should be placed in cloud-api/cloud-engine-api packages
- Access permissions: The command's access control permissions (who is eligible to call should be registered in commands.properties.in file
- Command registration: The command should be added to the list of all APIs CS supports, returned by ManagementServerImpl. getCommands()
Note that the calls done from the command, should reference only interfaces from cloud-api or cloud-util packages
![](/confluence/download/attachments/39622334/Relations.png?version=2&modificationDate=1394570795000&api=v2)
When command comes as a part of plugin/service
- Location: Define the command (request/response) in the plugin package
- Access Permissions: Define the permissions in the Cmd file, @APICommand annotation, "authorized" field. Example: authorized = {RoleType.Admin})
- Command Registration: Make your plugin manager to extent PluggableService interface. Add new API command to the list of commands returned by
getCommands()
The commands defined in the plugin, should reference only interfaces located in cloud-api/cloud-utils/<your plugin> packages
![](/confluence/download/attachments/39622334/relations_plugin.png?version=1&modificationDate=1394570807000&api=v2)
Rules when modify an existing APIs
The main rule is - all APIs should remain backwards compatible. It means that:
- Don't change the parameter from optional to required
- Don't add a new parameter to existing command with required=true option
- Don't reduce the command permission from being available to normal user, to becoming available to Admin only
- Don't rename existing parameters.
- Don't change the parameter type (from String to Map for example)
Other rules:
- When new parameter is added, it should be set with "since=release #" field in @Parameter annotation.
- If you think that some parameter should be removed in the future, mark it with @Deprecated and make sure its documented for the n release. Once its released, the customers will get a chance to review/change their code to get rid of this parameter, so it can be removed in the n+1 release.