API Endpoint

Table of contents

Loading...

Introduction

To allow an external client to interact with the backend application, an API access can be provided.

The API should be stateless, meaning that the server does not store any session information about the client. Each request from the client must contain all the information necessary to process the request.

Here are some best practices.

Allow client to make requests

Browsers have a security feature implemented to prevent unauthorized access and sharing of resources between different origins (domains, protocols, or ports). This is known as the same-origin policy, which allows scripts running on pages originating from the same site to make server requests with no specific restrictions, but prevents access to most methods and properties across pages on different sites.

This means that if a client is hosted on a different domain, it can't make requests to the backend application.

CORS is a mechanism that allows the server to tell the browser to relax the same-origin policy for its resources, and to allow specific cross-origin requests (i.e. requests from a different domain). This is done by the server sending specific HTTP headers that tell the browser which origins are allowed, which HTTP methods can be used, whether credentials can be included, and more.

The browser sends a "preflight" request to the server with the HTTP method OPTIONS to check if the server allows the actual request.

Enable CORS in Slim

To enable CORS in a Slim application, you can use a Middleware that adds the necessary headers to the response before sending it out.

Here is an example of a CORS Middleware that allows requests from any origin, with any HTTP method, and with credentials included.

File: src/Application/Middleware/CorsMiddleware.php

<?php

namespace App\Application\Middleware;

use App\Infrastructure\Utility\Settings;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

final readonly class CorsMiddleware implements MiddlewareInterface
{
    private ?string $allowedOrigin;

    public function __construct(private ResponseFactoryInterface $responseFactory, Settings $settings)
    {
        $this->allowedOrigin = $settings->get('api')['allowed_origin'] ?? null;
    }

    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        // Handle all "OPTIONS" pre-flight requests with an empty response
        // https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request
        if ($request->getMethod() === 'OPTIONS') {
            // Skips the rest of the middleware stack and returns the response
            $response = $this->responseFactory->createResponse();
        } else {
            // Continue with the middleware stack
            $response = $handler->handle($request);
        }
        // Add response headers in post-processing before the response is sent
        // https://samuel-gfeller.ch/docs/Middleware#order-of-execution
        $response = $response
            ->withHeader('Access-Control-Allow-Credentials', 'true')
            ->withHeader('Access-Control-Allow-Origin', $this->allowedOrigin ?? '*')
            ->withHeader('Access-Control-Allow-Headers', '*')
            ->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE, OPTIONS')
            ->withHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
            ->withHeader('Pragma', 'no-cache');

        // Handle warnings and notices, so they won't affect the CORS headers
        if (ob_get_contents()) {
            ob_clean();
        }

        return $response;
    }
}

To use the Middleware, you can add it to a specific route / route group or to the Middleware stack in the config/middleware.php file if it should be applied to all routes.

Add CORS middleware to a route group

Add cors headers to a specific route group only.

File: config/routes.php

// ...

$app->group('/api', function (RouteCollectorProxy $group) {
    $group->get('/example', ExampleAction::class);
    $group->post('/example', ExampleAction::class);
})->add(\App\Application\Middleware\CorsMiddleware::class);

// ...

Add CORS middleware to the middleware stack

Add cors headers to all routes.

File: config/middleware.php

return function (Slim\App $app) {

    // ...

    // Last middleware in the stack
    $app->add(\App\Application\Middleware\CorsMiddleware::class);
};

Read more

^