Define API endpoints

This page describes how to add an API endpoint to the Inmanta server. Adding a new API endpoint requires two methods: an API method and an API handle. The API method provides the specification of the endpoint. This includes the HTTP request method, the path to the endpoint, etc. The API handle on the other hand provides the actual implementation of the endpoint.

API Method

The Python function that acts as an API method should be annotated using the method decorator. The implementation of the method should be left empty.

An example is shown in the code snippet below.

import uuid
from inmanta.const import ClientType
from inmanta.protocol.decorators import method

@method(path="/project/<id>", operation="GET", client_types=[ClientType.api])
def get_project(id: uuid.UUID):
    """
        Get a project and a list of the ids of all environments.

        :param id: The id of the project to retrieve.
        :return: The project and a list of environment ids.
        :raises NotFound: The project with the given id doesn't exist.
    """

This API method defines an HTTP GET operation at the path /project/<id> which can be used by a client of type api (cli, dashboard and 3rd party service). The id parameter in the path will be passed to the associate API handle. A docstring can be associated with the API method. This information will be included in the OpenAPI documentation, available via the /docs endpoint of the Inmanta server.

A complete list of all the arguments accepted by the method decorator is given below.

decorators.method(operation: str = 'POST', reply: bool = True, arg_options: Dict[str, inmanta.protocol.common.ArgOption] = {}, timeout: Optional[int] = None, server_agent: bool = False, api: bool = None, agent_server: bool = False, validate_sid: bool = None, client_types: List[inmanta.const.ClientType] = [<ClientType.api: 'api'>], api_version: int = 1, api_prefix: str = 'api', envelope: bool = False, envelope_key: str = 'data') → Callable[, Callable]

Decorator to identify a method as a RPC call. The arguments of the decorator are used by each transport to build and model the protocol.

Parameters
  • path – The url path to use for this call. This path can contain parameter names of the function. These names should be enclosed in < > brackets.

  • operation – The type of HTTP operation (verb)

  • timeout – nr of seconds before request it terminated

  • api – This is a call from the client to the Server (True if not server_agent and not agent_server)

  • server_agent – This is a call from the Server to the Agent (reverse http channel through long poll)

  • agent_server – This is a call from the Agent to the Server

  • validate_sid – This call requires a valid session, true by default if agent_server and not api

  • client_types – The allowed client types for this call. The valid values are defined by the inmanta.const.ClientType enum.

  • arg_options

    Options related to arguments passed to the method. The key of this dict is the name of the arg to which the options apply. The value is another dict that can contain the following options:

    header: Map this argument to a header with the following name. reply_header: If the argument is mapped to a header, this header will also be included in the reply getter: Call this method after validation and pass its return value to the method call. This may change the

    type of the argument. This method can raise an HTTPException to return a 404 for example.

  • api_version – The version of the api this method belongs to

  • api_prefix – The prefix of the method: /<prefix>/v<version>/<method_name>

  • envelope – Put the response of the call under an envelope with key envelope_key.

  • envelope_key – The envelope key to use.

API Handle

An API handle function should be annotated with the handle decorator and should contain all the arguments of the associated API method and the parameters defined in the path of the endpoint. The names these arguments can be mapped onto a different name by passing arguments to the handle decorator.

An example is shown in the code snippet below.

import uuid
from inmanta.server import protocol
from inmanta.types import Apireturn
from inmanta import data
from inmanta.protocol import methods

@protocol.handle(methods.get_project, project_id="id")
async def get_project(self, project_id: uuid.UUID) -> Apireturn:
    try:
        project = await data.Project.get_by_id(project_id)
        environments = await data.Environment.get_list(project=project_id)

        if project is None:
            return 404, {"message": "The project with given id does not exist."}

        project_dict = project.to_dict()
        project_dict["environments"] = [e.id for e in environments]

        return 200, {"project": project_dict}
    except ValueError:
        return 404, {"message": "The project with given id does not exist."}

    return 500

The first argument of the handle decorator defines that this is the handle function for the get_project API method. The second argument remaps the id argument of the API method to the project_id argument in the handle function.

The arguments and the return type of the handle method can be any built-in Python type or a user-defined object. The input format of an API call be verified automatically using Pydantic.

An overview of all the arguments of the handle decorator are shown below.

class inmanta.protocol.decorators.handle(method: Callable[, Optional[Union[int, Tuple[int, Optional[Dict[str, Any]]], ReturnValue[ReturnTypes], ReturnValue[None], BaseModel, enum.Enum, uuid.UUID, inmanta.types.StrictNonIntBool, float, datetime.datetime, str, Sequence[Union[BaseModel, enum.Enum, uuid.UUID, inmanta.types.StrictNonIntBool, int, float, datetime.datetime, str]], Mapping[str, Union[BaseModel, enum.Enum, uuid.UUID, inmanta.types.StrictNonIntBool, int, float, datetime.datetime, str]]]]], api_version: Optional[int] = None, **kwargs: str)[source]

Decorator for subclasses of an endpoint to handle protocol methods

Parameters
  • method – A subclass of method that defines the method

  • api_version – When specific this handler is only associated with a method of the specific api verision. If the version is not defined, the handler is not associated with a rest endpoint.

  • kwargs – Map arguments in the message from one name to an other