Skip to content

API actions

This article would be useful for those who needs to create a custom API action.

Routing

You can define a specific route to access your API action (endpoint).

Default routes are defined here: application/Espo/Resources/routes.json.

Custom routes can be defined in the following places:

  • custom/Espo/Modules/{ModuleName}/Resources/routes.json
  • custom/Espo/Custom/Resources/routes.json

Example

routes.json

[
    {
        "route": "/MyAction",
        "method": "get",
        "actionClassName": "Espo\\Modules\\MyModule\\Api\\GetMyAction"
    },
    {
        "route": "/MyScope/:id/something",
        "method": "post",
        "actionClassName": "Espo\\Modules\\MyModule\\Api\\PostMyScopeSomething"
    },
    {
        "route": "/Hello/test/:id",
        "method": "get",
        "params": {
            "controller": "MyController",
            "action": "doSomething",
            "id": ":id"
        }
    },
    {
        "route": "/HelloWorld/:name",
        "method": "post",
        "params": {
            "controller": "MyController",
            "action": "helloWorld",
            "name": ":name"
        }
    },
    {
        "route": "/TestNoAuth",
        "method": "get",
        "params": {
            "controller": "Test",
            "action": "test"
        },
        "noAuth": true
    }
]

Route parameters:

  • noAuth makes the endpoint accessible without authentication.
  • method specifies an HTTP method. The most used methods are: get, post, put, delete.
  • actionClassName defines an action class name – the entry point of the route.
  • params – used for controller implementation, not recommeded.

A route can contain placeholders (for example, :id). The value will be passed to the Action in the Request object.

A route can be processed either by an Action class or by a Controller.

The API endpoint for a particular route: https://your-site/api/v1/{route}.

Clearing cache is required after changes in routing files.

Action

As of v7.4.

Note

This is the preferable method.

The actionClassName parameter in a route definition defines the action class. The action class is an entry point. Action classes should implement the Espo\Core\Api\Action interface.

Example:

<?php
namespace Espo\Modules\MyModule\Api;

use Espo\Core\Api\Action;
use Espo\Core\Api\Request;
use Espo\Core\Api\Response;
use Espo\Core\Api\ResponseComposer;
use Espo\Core\Exceptions\BadRequest;

use RuntimeException;

use Espo\Modules\MyModule\Service;

class GetMyAction implements Action
{
    public function __construct(
        // Some class we delegate the logic to.
        private Service $service,
    ) {}

    public function process(Request $request): Response
    {
        // A route parameter value is passed in an URI, if defined in the route.
        // E.g. `/Hello/:id`.
        $id = $request->getRouteParam('id') ?? throw new RuntimeException();

        // Read payload.
        $someInputValue = $request->getParsedBody()->someKey ??
            throw new BadRequest("Key is not passed in payload.");

        // Delegate the logic to some class.
        $data = $this->service->get($id, $someInputValue);

        // Output the result as JSON.
        return ResponseComposer::json([
            'someKey' => $data->someKey,
        ]);
    }
}

For most cases, the sections below won't be relevant and can be skipped.

Custom controller

Note

This is not a preferable method.

Alternative to an Action class. A Controller can contain multiple methods for different actions.

In Custom folder

Create a file custom/Espo/Custom/Controllers/MyController.php.

<?php
namespace Espo\Custom\Controllers;

class MyController
{}

Clear cache (Administration > Clear Cache).

In Module folder

Create a file custom/Espo/Modules/MyModule/Resources/metadata/scopes/MyController.json.

{
    "module": "MyModule"
}

Create a file custom/Espo/Modules/MyModule/Controllers/MyController.php.

<?php
namespace Espo\Modules\MyModule\Controllers;

class MyController
{
    // Dependencies are passed to the constructor.
}

Clear cache after creating a new controller (Administration > Clear Cache).

Example:

<?php
namespace Espo\Modules\MyModule\Controllers;

use Espo\Core\Api\Request;
use Espo\Core\Api\Response;
use SomeDependency;
use stdClass;

class MyController
{
    public function __construct(private SomeDependency $someDependency)
    {}

    // Naming convention: `{method}Action{Action}`.
    public function putActionUpdate(Request $request, Response $response): stdClass
    {
        $id = $request->getRouteParam('id');
        $data = $request->getParsedBody();

        $result = $this->someDependency->doSomething($id, $data);

        // Response can be returned or written with `Response::writeBody`.
        return $result->toStdClass();
    }
}

Extending existing controller

Note

Not recommended.

Example for the Account scope.

Create a file (or modify if it already exists) custom/Espo/Custom/Controllers/Account.php.

<?php
namespace Espo\Custom\Controllers;

use Espo\Core\Api\Request;
use Espo\Core\Api\Response;

class Account extends \Espo\Modules\Crm\Controllers\Account
{
    /**
     * POST api/v1/Account/action/test
     */
    public function postActionTest(Request $request, Response $response): bool
    {
        $someParam = $request->getQueryParam('someParam'); // GET parameter        
        $data = $request->getParsedBody(); // payload

        $someValue = $data->someKey ?? null;

        $response->setStatus(201); // example how to set custom response status code

        // call some service class here

        return $someData; // can be true, false, array or object.
    }

    /**
     * GET api/v1/Account/action/test
     */
    public function getActionTest(Request $request, Response $response): void
    {
        $someParam = $request->getQueryParam('someParam'); // GET parameter

        // call some service class here

        $response->writeBody('true');
    }
}

Note

For the Account entity type, we extend Espo\Modules\Crm\Controllers\Account. Some entity types might not have controllers in Espo\Modules\Crm\Controllers namespace. They are defined in Espo\Controllers namespace.

CRUD actions

If a controller is used, the CRUD operations for a record are implemented using the methods shown below.

<?php
namespace Espo\Custom\Controllers;

use Espo\Core\Api\Request;
use Espo\Core\Api\Response;

class MyController
{   
    // Creates a record.
    public function postActionCreate(Request $request, Response $response): void
    {}

    // Reads a record.
    public function getActionRead(Request $request, Response $response): void
    {}

    // Updates a record.
    public function putActionUpdate(Request $request, Response $response): void
    {}

    // Deletes a record.
    public function deleteActionDelete(Request $request, Response $response): void
    {}
}