Skip to content

API Instance

An API instance holds all the services. You can also define system-wide request hooks, which will apply to every endpoint. Read more about hooks.

php
$api = new Api();

Configuration

Use configure() to configure the main instance.

php
$api->configure(function ($config) {
  // Should endpoint paths end with a trailing slash?
  // (null = no preference)
  $config->trailingSlashes = null;

  // Flags to pass to the json_encode function
  $config->jsonFlags = JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES;
});

Base path

All endpoint paths will be prefixed with the base path. You can set a custom base path with setBasePath(). The default value is /.

php
$api->setBasePath('/api');

Adding a service

Call addService() to attach a service to the API.

php
$api->addService(new HelloWorldService());

The newly added service can be accessed in an optional setup function. This can be used to reconfigure the service, add child services, define hooks, etc.

php
$api->addService(new HelloWorldService(), function ($service) {
  // Override the default base path
  $service->setBasePath('/greet');

  // Add a child service
  $service->addService(new AnotherService());
});

Running the API

Call run() to register all endpoint listeners and start handling requests. This should be called after all services and configuration have been set up.

php
$api->run();

Under the hood, the method:

  1. Iterates all registered services and their endpoints
  2. Validates that there are no duplicate service names or endpoint paths
  3. Registers a ProcessWire URL hook listener for each endpoint path

TIP

For a complete overview of the initialization and request handling sequence, see Application lifecycle.

Locking

After run() is called, the Api instance, all services, and all endpoints are locked. Locked objects reject structural mutations — this includes adding services, endpoints, plugins, hooks, and setting endpoint handlers.

All configuration must happen either in a service's init() method or in the addService() setup callback.

A WireException is thrown if a mutation is attempted after locking.

Exception handling

Due to the nature of ProcessWire URL hooks, exceptions thrown in hook code cannot be caught in the main program flow. Use handleException() to define your own exception handler for other exception types, such as WireException.

You can access the following properties via the $args parameter of the handler function.

PropertyTypeDescription
exception\ThrowableException
requestRequestRequest object
event\ProcessWire\HookEventProcessWire URL hook event
endpointEndpointRequested endpoint
serviceServiceRequested service
servicesServiceListList of all parent services
apiApiAPI instance

You need to return either a Response or an ApiException from the handler.

php
$api->handleException(function ($args) {
  // Handle WireExceptions
  if ($args->exception instanceof WireException) {
    return (new ApiException())->code(500)->with([
      'message' => $args->exception->getMessage(),
    ]);
  }

  return (new ApiException())->code(400)->with([
    'message' => $args->exception->getMessage(),
  ]);
});

Multiple instances

You can create multiple API instances, each with its own configuration, services, and hooks. This can be useful for API versioning.

TIP

To avoid path clashes, it's highly recommended to set unique base paths for all instances.

php
$v1 = new Api();
$v1->setBasePath('/v1');
$v1->run();

$v2 = new Api();
$v2->setBasePath('/v2');
$v2->run();

Released under the MIT License.