Usage

The package main functionality is implemented as a MATLAB class prodserver.openapi with various configuration options and a generate method which generates a YAML OpenAPI specification based on a MATLAB Production Server Discovery document (imported as MATLAB structure); the document is returned as string.

It is possible to build your own higher level functionality, which for example first downloads and parses the discovery document into a struct and which writes the resulting document to file, on top of this.

An example wrapper function is included in the package which can help deploying the functionality as an endpoint to MATLAB Production Server itself, also see Deploy as endpoint to MATLAB Production Server.

prodserver.openapi

The prodserver.openapi class has various properties with which the behavior of the generator can be configured.

OpenAPIVersion:

Generate an OpenAPI Specification compatible with the specified OpenAPI version.
Type: string
Default: "3.0.3"
Valid options: "3.0.3", "3.1.0"

Version:

Sets the version of the OpenAPI document (which is distinct from the the OpenAPI Specification Version as set by OpenAPIVersion). It for example makes sense to change this version number if CTFs are added or removed from the server or if functions are added or removed from a package or if the in- or outputs of a function change, i.e. anything which changes the “interface” of the RESTful API which consumers can call. This allows consumers of the APIs to clearly recognize when the interfaces have changed and they can for example more easily recognize that they might be working with a outdated copy of the specification (and they need to obtain a new version). Since the package cannot automatically track what may- or may not have changed over time on the MATLAB Production Server instance, the version number which is included in the generated document must be manually configured through this property.
Type: string
Default: "1.0.0"

Server:

Specifies the server addresses to be included in the specification. This is a hint to the consumers of the specification to indicate which server(s) they can work with when consuming your API. Consumers can choose to ignore this and can typically connect to other instances (serving the same functionality) as well.
Type: string scalar or array
Default: "http://localhost:9910/"

HeterogeneousArraySpecifier:

Specifies how items are defined for heterogenous arrays in 3.0.3 format. This can be done using an anyOf or oneOf schema. The official OpenAPI 3.0.3 is unclear about which option should be used (also see Heterogenous array item definition) therefore this can be user configured.
Type: string
Default: "anyOf"
Valid options: "anyOf", "oneOf"

Async:

Specifies whether or not to include the asynchronous interface in the generated spec. Note that since the output of the result endpoint depends on which function the result is being retrieved for, its response cannot be accurately described in the generated spec and is therefore simply defined as to return “an object” with no further details. For documentation purposes it does refer back to the outputs of the synchronous versions of the function calls.
Type: logical
Default: false

OAuth:

Includes authentication information in the spec. For example, enable this if the server is configured with OAuth based Application Access Control. When enabling this options, also configure AuthorizationUrl and TokenUrl.
Type: logical
Default: false

AuthorizationUrl:

When OAuth == true specifies the Authorization URL to include with the authentication information in the spec.
Type: string
Default: "https://www.example.com/auth"

TokenUrl:

When OAuth == true specifies the Token URL to include with the authentication information in the spec.
Type: string
Default: "https://www.example.com/token"

Properties can be set after instantiating the object instance:

openapiGenerator = prodserver.openapi();
openapiGenerator.Version = "3.14.0";
openapiGenerator.Async = true;

Or alternatively it is also possible to pass the properties and their desired values as name-value pairs to the constructor, for example:

openapiGenerator = prodserver.openapi('Version', '3.14.0', 'Async', true);

or:

openapiGenerator = prodserver.openapi(Version="3.14.0", Async=true);

Examples

%% Create the generator instance
openapiGenerator = prodserver.openapi();

%% Configure the generator instance
% For example, specify the version of the API
openapiGenerator.Version = "3.14.0";
% For example, specify that the asynchronous interface should be included in the spec
openapiGenerator.Async = true;

%% Use the generate method on a MATLAB Production Server Discovery document imported as MATLAB structure
% For example, query the live discovery endpoint of a MATLAB Production Server Instance
discovery = webread("http://localhost:9910/api/discovery");
% Or alternatively, it is also possible to read a previously downloaded document
% discovery = jsondecode(fileread("discovery.json"));

% Call the generate method on the structure
openApiSpec = openapiGenerator.generate(discovery);

% This returned a string representation of the OpenAPI spec in YAML format.
% For example, display it
disp(openApiSpec)

Important Notes

As noted in the main package description, the package translates the proprietary JSON format of MATLAB Production Server’s Discovery Service into OpenAPI specifications. It is therefore important to note that it will only be able to generate OpenAPI specs for functionality for which discovery information is in fact available. It is up to archive authors to ensure this information is included in the archive and the included information is correct. If a function is not included in the discovery document it will not show up in the generated OpenAPI spec. If an archive does not contain discovery information at all, the entire archive will not show up in the generated OpenAPI spec either.

Similarly, the accuracy of the generated OpenAPI spec will depend on the accuracy of the discovery information. For example, if the size of a variable is not specified in the discovery document, the generated OpenAPI spec will also lack this piece of information.

Also, if there are mistakes in the discovery information, the generated OpenAPI spec will likely be inaccurate as well. The package does not dynamically verify the validity of the discovery document before translation, nor does it verify the correctness of the generated OpenAPI spec after generation. I.e. it does not try to invoke the function based on the original or generated spec to verify its correctness against the deployed functionality.

Further usage

Deployed as endpoint on MATLAB Production Server

To learn more about how to deploy the OpenAPI generator as an endpoint on MATLAB Production Server itself, see Deploy as endpoint to MATLAB Production Server.

As MATLAB Compiler standalone application

To be able to use the tooling outside of MATLAB without needing a MATLAB license, it is possible to first write a wrapper function, for example:

Software/MATLAB/examples/standalone/productionServerOpenAPI.m
function productionServerOpenAPI(infile,outfile)
% PRODUCTIONSERVEROPENAPI example MATLAB function which can be compiled
% into a MATLAB Compiler Standalone application which can then be used to
% translate MATLAB Production Server discovery documents into OpenAPI
% specs.
%
% The code below can be updated to configure the generator according to
% your own needs (e.g. the OpenAPI version can be changed).
%
% To compile:
%
% >> compiler.build.standaloneApplication("productionServerOpenAPI")
%
% Then from a Windows or Linux command prompt:
%
% > productionServerOpenAPI "http://localhost:9910/api/discovery" "openapi.yaml"

% Copyright 2023-2024 The MathWorks, Inc.

    if startsWith(infile,"http")
        % If the input starts with http use "webread" to read the discovery
        % information
        discovery = webread(infile);
    else
        % If it does not start with http, assume a local file and read it
        discovery = jsondecode(fileread(infile));
    end
    % Create the generator instance
    openapiGenerator = prodserver.openapi();
    % Optional: configure settings, for example enable the asynchronous
    % interface
    openapiGenerator.Async = true;
    % Run the generator
    openApiSpec = openapiGenerator.generate(discovery);
    % Write the output to the specified output file
    f = fopen(outfile,'w');
    fwrite(f,openApiSpec);
    fclose(f);

And then compile this into a MATLAB Compiler standalone application:

>> compiler.build.standaloneApplication("productionServerOpenAPI.m")

This can then be used on any system with the correct MATLAB Runtime version installed. For example, on Linux:

$ ./productionServerOpenAPI "http://localhost:9910/api/discovery" "myspec.yaml"

or on Windows:

C:\Work>productionServerOpenAPI.exe "http://localhost:9910/api/discovery" "myspec.yaml"

The wrapper can be further customized to configure the generator differently or for example, print the output rather than write it to file or allow end-user to specify addition/other inputs on the command line.

In CI/CD pipelines

To use the generator in CI/CD pipelines it is possible to first compile the generator into a standalone application as discussed in the previous section and then call the standalone application from a CI/CD script.

Alternatively, it is possible to simply run as MATLAB code inside MATLAB see the Continuous Integration (CI) section in the MATLAB documentation to learn more about using MATLAB in CI/CD pipelines.