Zed API feature integration

Edit on GitHub

This document describes how to install the Zed API feature.

Install feature core

Follow the steps below to install the Zed API feature core.

Prerequisites

To start feature integration, integrate the required features and Glue APIs:

NAME VERSION INSTALLATION GUIDE
Spryker Core 202204.0 Spryker Сore feature integration

1) Install the required modules using Composer

Install the required modules:

composer require spryker/api:"^0.4.0" --update-with-dependencies
Verification

Make sure that the following modules have been installed:

MODULE EXPECTED DIRECTORY
Api vendor/spryker/api
ApiExtension vendor/spryker/api-extension

2) Set up the configuration

Add the following configuration:

CONFIGURATION SPECIFICATION NAMESPACE
ApiConstants::ENABLE_API_DEBUG Enables the mode when API response is extended with request parameters and stacktrace. Spryker\Shared\Api
ApiConfig::isApiEnabled() Enables Zed API. Spryker\Zed\Api
ApiConfig::getAllowedOrigin() Defines the CORS Access-Control-Allowed-Origin header. Spryker\Zed\Api
ApiConfig::getSafeHeaderDataKeys() Defines allowed headers. Spryker\Zed\Api
ApiConfig::getSafeServerDataKeys() Defines allowed server data keys. Spryker\Zed\Api

config/Shared/config_default.php

<?php

use Spryker\Shared\Api\ApiConstants;

// >>> Debug
$config[ApiConstants::ENABLE_API_DEBUG] = (bool)getenv('SPRYKER_DEBUG_ENABLED');
src/Pyz/Zed/Api/ApiConfig.php
<?php

/**
 * This file is part of the Spryker Suite.
 * For full license information, please view the LICENSE file that was distributed with this source code.
 */

namespace Pyz\Zed\Api;

use Spryker\Zed\Api\ApiConfig as SprykerApiConfig;

class ApiConfig extends SprykerApiConfig
{
    /**
     * @api
     *
     * @return bool
     */
    public function isApiEnabled(): bool
    {
        return true;
    }

    /**
     * @api
     *
     * @return string|null
     */
    public function getAllowedOrigin(): ?string
    {
        return '*';
    }

    /**
     * @return array<string>
     */
    public function getSafeHeaderDataKeys(): array
    {
        return [
            'accept-language',
            'accept-encoding',
            'accept',
            'range',
            'origin',
            'user-agent',
            'upgrade-insecure-requests',
            'cache-control',
            'connection',
            'host',
            'x-request-start',
            'content-length',
            'content-type',
            'x-php-ob-level',
        ];
    }

    /**
     * @return array<string>
     */
    public function getSafeServerDataKeys(): array
    {
        return [
            'VM_DOMAIN',
            'VM_PROJECT',
            'USER',
            'HOME',
            'HTTP_ACCEPT_LANGUAGE',
            'HTTP_ACCEPT_ENCODING',
            'HTTP_ACCEPT',
            'HTTP_USER_AGENT',
            'HTTP_UPGRADE_INSECURE_REQUESTS',
            'HTTP_CACHE_CONTROL',
            'HTTP_CONNECTION',
            'HTTP_HOST',
            'APPLICATION_STORE',
            'APPLICATION_ENV',
            'HTTP_X_REQUEST_START',
            'HTTPS',
            'REDIRECT_STATUS',
            'SERVER_NAME',
            'SERVER_PORT',
            'SERVER_ADDR',
            'REMOTE_PORT',
            'REMOTE_ADDR',
            'SERVER_SOFTWARE',
            'GATEWAY_INTERFACE',
            'SERVER_PROTOCOL',
            'DOCUMENT_ROOT',
            'DOCUMENT_URI',
            'REQUEST_URI',
            'SCRIPT_NAME',
            'SCRIPT_FILENAME',
            'CONTENT_LENGTH',
            'CONTENT_TYPE',
            'REQUEST_METHOD',
            'QUERY_STRING',
            'FCGI_ROLE',
            'PHP_SELF',
            'REQUEST_TIME_FLOAT',
            'REQUEST_TIME',
        ];
    }
}
Verification

Make sure that Zed API is enabled by accessing any backend API resource.

Make sure that the backend API is extended with request parameters and stacktrace when ApiConstants::ENABLE_API_DEBUG is set to true.

3) Set up transfer objects

Generate transfers:

console transfer:generate
Verification

Ensure the following transfers have been created:

TRANSFER TYPE EVENT PATH
ApiRequest class created src/Generated/Shared/Transfer/ApiRequestTransfer.php
ApiResponse class created src/Generated/Shared/Transfer/ApiResponseTransfer.php
ApiValidationError class created src/Generated/Shared/Transfer/ApiValidationErrorTransfer.php
ApiFilter class created src/Generated/Shared/Transfer/ApiFilterTransfer.php
ApiData class created src/Generated/Shared/Transfer/ApiDataTransfer.php
ApiPagination class created src/Generated/Shared/Transfer/ApiPaginationTransfer.php
ApiCollection class created src/Generated/Shared/Transfer/ApiCollectionTransfer.php
ApiItem class created src/Generated/Shared/Transfer/ApiItemTransfer.php
ApiOptions class created src/Generated/Shared/Transfer/ApiOptionsTransfer.php
ApiMeta class created src/Generated/Shared/Transfer/ApiMetaTransfer.php

4) Set up behavior

Enable the following behaviors by registering the plugins:

PLUGIN SPECIFICATION PREREQUISITES NAMESPACE
ApiRouterPlugin Provides Router which handles backend API calls. Spryker\Zed\Api\Communication\Plugin\Router
MonitoringRequestTransactionEventDispatcherPlugin Adds subscriber to listen for controller events. Spryker\Zed\Monitoring\Communication\Plugin\EventDispatcher
RouterListenerEventDispatcherPlugin Adds a RouteListener to the EventDispatcher. Spryker\Zed\Router\Communication\Plugin\EventDispatcher
ResponseListenerEventDispatcherPlugin Adds a ResponseListener to the EventDispatcher. Spryker\Shared\Http\Plugin\EventDispatcher
ApiControllerEventDispatcherPlugin Adds a listener for the KernelEvents::CONTROLLER event to execute an ApiController if current request is an API request. Spryker\Zed\Api\Communication\Plugin\EventDispatcher
AutoloaderCacheEventDispatcherPlugin Adds a listener for the KernelEvents::TERMINATE event, which will write a class resolver cache. Spryker\Zed\Kernel\Communication\Plugin
ApiRequestTransferFilterHeaderDataPlugin Filters out ApiRequestTransfer headers that are not specified in ApiConfig::getSafeHeaderDataKeys(). Spryker\Zed\Api\Communication\Plugin
ApiRequestTransferFilterServerDataPlugin Filters out ApiRequestTransfer server data that are not specified in ApiConfig::getSafeServerDataKeys(). Spryker\Zed\Api\Communication\Plugin

src/Pyz/Zed/Router/RouterDependencyProvider.php

<?php

namespace Pyz\Zed\Router;

use Spryker\Zed\Api\Communication\Plugin\Router\ApiRouterPlugin;
use Spryker\Zed\Router\RouterDependencyProvider as SprykerRouterDependencyProvider;

class RouterDependencyProvider extends SprykerRouterDependencyProvider
{
    /**
     * @return array<\Spryker\Zed\RouterExtension\Dependency\Plugin\RouterPluginInterface>
     */
    protected function getBackendApiRouterPlugins(): array
    {
        return [
            new ApiRouterPlugin(),
        ];
    }
}

src/Pyz/Zed/EventDispatcher/EventDispatcherDependencyProvider.php

<?php

namespace Pyz\Zed\EventDispatcher;

use Spryker\Shared\Http\Plugin\EventDispatcher\ResponseListenerEventDispatcherPlugin;
use Spryker\Zed\Api\Communication\Plugin\EventDispatcher\ApiControllerEventDispatcherPlugin;
use Spryker\Zed\EventDispatcher\EventDispatcherDependencyProvider as SprykerEventDispatcherDependencyProvider;
use Spryker\Zed\Kernel\Communication\Plugin\AutoloaderCacheEventDispatcherPlugin;
use Spryker\Zed\Monitoring\Communication\Plugin\EventDispatcher\MonitoringRequestTransactionEventDispatcherPlugin;
use Spryker\Zed\Router\Communication\Plugin\EventDispatcher\RouterListenerEventDispatcherPlugin;

class EventDispatcherDependencyProvider extends SprykerEventDispatcherDependencyProvider
{
    /**
     * @return array<\Spryker\Shared\EventDispatcherExtension\Dependency\Plugin\EventDispatcherPluginInterface>
     */
    protected function getBackendApiEventDispatcherPlugins(): array
    {
        return [
            new MonitoringRequestTransactionEventDispatcherPlugin(),
            new RouterListenerEventDispatcherPlugin(),
            new ResponseListenerEventDispatcherPlugin(),
            new ApiControllerEventDispatcherPlugin(),
            new AutoloaderCacheEventDispatcherPlugin(),
        ];
    }
}

src/Pyz/Zed/Api/ApiDependencyProvider.php

<?php

namespace Pyz\Zed\Api;

use Spryker\Zed\Api\ApiDependencyProvider as SprykerApiDependencyProvider;
use Spryker\Zed\Api\Communication\Plugin\ApiRequestTransferFilterHeaderDataPlugin;
use Spryker\Zed\Api\Communication\Plugin\ApiRequestTransferFilterServerDataPlugin;

class ApiDependencyProvider extends SprykerApiDependencyProvider
{
    /**
     * @return array<\Spryker\Zed\Api\Communication\Plugin\ApiRequestTransferFilterPluginInterface>
     */
    protected function getApiRequestTransferFilterPluginCollection(): array
    {
        return [
            new ApiRequestTransferFilterServerDataPlugin(),
            new ApiRequestTransferFilterHeaderDataPlugin(),
        ];
    }
}

Create a new entry point for Zed API Application:

public/BackendApi/index.php

<?php

use Spryker\Shared\Config\Application\Environment;
use Spryker\Shared\ErrorHandler\ErrorHandlerEnvironment;
use Spryker\Zed\Application\Communication\Bootstrap\BackendApiBootstrap;

define('APPLICATION', 'ZED');
defined('APPLICATION_ROOT_DIR') || define('APPLICATION_ROOT_DIR', dirname(__DIR__, 2));

require_once APPLICATION_ROOT_DIR . '/vendor/autoload.php';

Environment::initialize();

$errorHandlerEnvironment = new ErrorHandlerEnvironment();
$errorHandlerEnvironment->initialize();

$bootstrap = new BackendApiBootstrap();
$bootstrap
    ->boot()
    ->run();

5) Configure web server

Create Nginx VHOST configuration:

/etc/nginx/sites-enabled/DE_development_glue

<?php

server {
	# Listener for production/staging - requires external LoadBalancer directing traffic to this port
	listen 10001;

	# Listener for testing/development - one host only, doesn't require external LoadBalancer
	listen 80;

	server_name ~^zed-api\\..+\\.com$;

	keepalive_timeout 0;
	access_log  /data/logs/development/zed-api-access.log extended;

	# entry point for Glue Application
	root /data/shop/development/current/public/BackendApi;

	set $application_env development;
	# Binding store
	set $application_store DE;
	include "spryker/zed.conf";
}

Update hosts configuration by adding the following line (replace IP with your server’s IP address):

/etc/hosts

ip zed-api.mysprykershop.com
“Verification”

If everything is set up correctly, you should be able to access http://zed-api.mysprykershop.com.