Defining a new API
To create a new API, follow these steps as detailed below:
- Create the API Automation script
- Create the API definition(s) and token(s)
- Configure the UserDefinableApiEndpoint extension module
Note
This is the recommended workflow when creating new APIs using new scripts. If you want to use an existing script for the API, see Using existing scripts.
Creating the API Automation script
To define an API, you will need an Automation script that contains the logic of the API. This Automation script needs the OnApiTrigger
entry point method, which will be executed when the API is triggered. The entry point should look like this:
using Skyline.DataMiner.Automation;
using Skyline.DataMiner.Net.Apps.UserDefinableApis;
using Skyline.DataMiner.Net.Apps.UserDefinableApis.Actions;
public class Script
{
[AutomationEntryPoint(AutomationEntryPointType.Types.OnApiTrigger)]
public ApiTriggerOutput OnApiTrigger(IEngine engine, ApiTriggerInput requestData)
{
var method = requestData.RequestMethod;
var route = requestData.Route;
var body = requestData.RawBody;
return new ApiTriggerOutput
{
ResponseBody = $"Received {method} request for route: '{route}' with body: '{body}'",
ResponseCode = (int) StatusCode.Ok,
};
}
}
Note
- When developing the API script in DIS, make sure to update the Skyline.DataMiner.Dev.Automation NuGet package to its latest version so the types of the User-Defined APIs feature are available.
- The
Run
method is not required in the script, but the entry point method must reside in theScript
class, just like in any other DataMiner scripts.
Input
The entry point method has two parameters.
The
IEngine
object can be used to interact with the DataMiner Automation engine.The
ApiTriggerInput
is an object that contains information about the API trigger. It has the following properties:Property Type Description RequestMethod RequestMethod
The HTTP method of the request. See RequestMethod. Route string
The suffix of the URL that this API call is triggered with. Having this available makes it possible to reuse the same script for different routes. See Route. RawBody string
The full body of the HTTP request as a string. This can be deserialized and used in the script. See User input data. Parameters Dictionary<string, string>
Contains the deserialized parameters if you select Dictionary (parsed from JSON) when configuring the API. See User input data. Context ApiTriggerContext Contains properties with info about the request. Available from DataMiner 10.3.9/10.4.0 onwards. QueryParameters IQueryParameters Contains the request query string parameters. Available from DataMiner 10.4.1/10.5.0 onwards.
ApiTriggerContext
Property | Type | Description |
---|---|---|
TokenId | Guid |
Contains the ID of the ApiToken with which the API is triggered. Available from DataMiner 10.3.9/10.4.0 onwards. |
RequestMethod
You can use the RequestMethod property to check the HTTP method of the trigger. It can contain the following values:
- Get
- Put
- Post
- Delete
This makes it possible to define the four CRUD (create, read, update, delete) actions in one script. If one or more methods should not be used, you can return a status code 405 (see ResponseCode).
User input data
There are two ways to pass data to the API:
- You can use query parameters, which allow you to pass data in a key-value format.
- You can use the request body, which you can either deserialize yourself in your script, or you can have deserialized to a key-value format by the built-in deserialization.
Query parameters
Query parameters are available in the QueryParameters property in the ApiTriggerInput
. IQueryParameters
exposes the following methods:
Method name | Return type | Summary |
---|---|---|
TryGetValues(string key, out List<string> values) |
bool |
Tries to get the values for the associated key. Returns true in case one or more values are found for the key, and false if not. The values will be in the out parameter. |
TryGetValue(string key, out string value) |
bool |
Tries to get the value for the associated key. Returns true in case a value is found for the key, and false if not. The value will be in the out parameter. In case there are multiple values, the first value will be returned. |
GetAllKeys() |
List<string> |
Returns all keys for which there is a value. |
ContainsKey(string key) |
bool |
Returns whether the key is present or not. |
Note
- Multiple values can be added for one key.
- Query parameter keys are case-sensitive.
- The maximum size for the query string is 2 KB.
- Query parameters are available from DataMiner 10.4.1/10.5.0 onwards.
Request body
There are two ways to pass the request body to the API script if you make use of the OnApiTrigger entry point method. Which way is used depends on the selected option in the dropdown when you define the API in Cube. See Creating the API definition(s).
If Dictionary (parsed from JSON) is selected, the JSON body of the HTTP request will automatically be converted to a
Dictionary<string, string>
in theParameters
property of theApiTriggerInput
object. In theRawBody
property, the raw string body will remain available.Note
Note that only JSON in the form of key-value pairs is accepted as parameters. For example:
{ "userName" : "JohnDoe", "limit" : "10" }
If the default option Raw body is selected, the
Parameters
property will contain an emptyDictionary<string, string>
. In this case, you will need to take care of the deserialization of the raw body string which can be found in theRawBody
property.
Tip
To see how these two options are used in an API script, see API script examples.
Route
The route describes the URL route where the API will be available. It is a suffix that comes after the base URL {hostname}/api/custom/
.
- The route must not start or end with a forward slash (
/
). - The route must be unique for each API definition. When it is saved, DataMiner will automatically check this to prevent conflicts.
- Routes are case-insensitive.
For example, if you want to create an API to retrieve the status of all encoders in your system, a logical route would be encoders/status
. The full API call would then look like this:
HTTP GET mydataminer.customer.local/api/custom/encoders/status
Tip
We recommend that you keep routes simple and straightforward. For some great tips on this, refer to restfulapi.net.
Output
The entry point method returns an instance of the ApiTriggerOutput
class. This will be used to determine the response to the API caller.
The ApiTriggerOutput
object has the following properties:
Property | Type | Description |
---|---|---|
ResponseCode | int | The HTTP status code. See ResponseCode. |
ResponseBody | string | Contains the response body as a string. The size of this response body is limited to 29 MB. |
Note
A valid output instance always has to be returned.
ResponseCode
The status of the API trigger request is reflected in the ResponseCode
property of the ApiTriggerOutput
. This is an integer, so any valid HTTP status code can be passed here.
You can also use the StatusCode
enum, which contains suggestions, and cast that to an integer. These are the values of the enum:
Name | Value | Description |
---|---|---|
Ok | 200 | The request got executed successfully. |
Created | 201 | The request succeeded, and a new resource was created as a result. |
Accepted | 202 | The request was received, but not executed yet. Could be used for long-running async actions. |
NoContent | 204 | There is no content to return for the request, but the request did succeed. |
BadRequest | 400 | There was a client error, e.g. wrong parameters. |
NotFound | 404 | The requested document was not found. |
MethodNotAllowed | 405 | The HTTP method is not valid for this request. For example DELETE is used while GET was expected. |
InternalServerError | 500 | Return this if something went wrong in your Automation script, e.g. you try to write to a file, but the file is in use by another application. |
Tip
For more insight into which HTTP status codes to use in which circumstances, see HTTP status codes.
Creating an API and tokens in DataMiner Automation
Note
- Before you try to execute this procedure, make sure you have the user permissions available under Modules > User-Defined APIs.
- You can also create an API and tokens directly in code, for example if an API setup needs to be deployed in the install script of an application package. See Creating APIs and tokens in code.
Open your API script in the Automation module in DataMiner Cube and click Configure API at the bottom of the window.
This will open a window where you can create the API.
Creating an API in DataMiner 10.3.6Note
You will only be able to see the button Configure API in the UI if the following conditions are met:
- You are using DataMiner 10.3.6 or higher.
- The DataMiner System has an active Indexing Engine (e.g. Elasticsearch).
- You have the permission to read API definitions.
Add a description (optional).
In the URL box, specify the unique route.
If you want to parse the JSON body of the HTTP request to a dictionary, make sure Dictionary (parsed from JSON) is selected. See User input data.
Note
Leave Method to be executed set to the default selection. This option should only be changed for legacy scripts without the
OnApiTrigger
entry point. See Using existing scripts.Under Tokens, select the tokens that need access. You can also create new tokens using the New token button.
Note
At least one token has to be linked before the API will be usable.
Caution
Once a token is created with a specified secret, it is not possible to retrieve that secret again. The value is stored securely in the database with a non-reversible hashing function. Make sure to save it somewhere secure or pass it in a secure way to the API user.
Note
You can change your API configuration at any time on the User-Defined APIs page in System Center. Alternatively, you can also open this window in the Automation module again to change the settings.
Configuring the UserDefinableApiEndpoint extension module
Make sure the UserDefinableApiEndpoint DxM has been configured to match your API needs. For more information, refer to UserDefinableApiEndpoint configuration.
If you have already configured the DxM, there is no need to repeat this step for each user-defined API you create.