Drupal REST/JSON:API Integration Development

Our company is engaged in the development, support and maintenance of sites of any complexity. From simple one-page sites to large-scale cluster systems built on micro services. Experience of developers is confirmed by certificates from vendors.
Development and maintenance of all types of websites:
Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Our competencies:
Development stages
Latest works
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    822
  • image_crm_chasseurs_493_0.webp
    CRM development for Chasseurs
    847
  • image_website-sbh_0.png
    Website development for SBH Partners
    999
  • image_website-_0.png
    Website development for Red Pear
    451

Developing REST/JSON:API Integration for Drupal

Drupal comes with two API systems out of the box: REST (flexible, requires configuration) and JSON:API (standardized, works immediately). JSON:API is preferable for headless architectures and mobile applications.

JSON:API — Enabling and First Requests

drush en jsonapi -y

After enabling, all content types are automatically available. URL format: /jsonapi/{entity_type}/{bundle}.

# List of articles
curl https://site.com/jsonapi/node/article

# Specific node by UUID
curl https://site.com/jsonapi/node/article/{uuid}

# Filtering
curl "https://site.com/jsonapi/node/article?filter[status]=1&filter[field_category.name]=News"

# Including related resources
curl "https://site.com/jsonapi/node/article?include=field_tags,uid"

# Sorting and pagination
curl "https://site.com/jsonapi/node/article?sort=-created&page[limit]=10&page[offset]=20"

# Selecting specific fields (sparse fieldsets)
curl "https://site.com/jsonapi/node/article?fields[node--article]=title,body,created"

Authentication for Writing

JSON:API supports GET without authentication (for public content). POST/PATCH/DELETE require authentication.

# Basic authentication (development only)
curl -X POST https://site.com/jsonapi/node/article \
    -u admin:password \
    -H "Content-Type: application/vnd.api+json" \
    -d '{
        "data": {
            "type": "node--article",
            "attributes": {
                "title": "New Article",
                "body": { "value": "<p>Text</p>", "format": "full_html" }
            }
        }
    }'

For production — OAuth 2.0 via simple_oauth module:

composer require drupal/simple_oauth
drush en simple_oauth -y

Simple OAuth: Configuration

  1. Configuration → Simple OAuth → Generate keys
  2. Create OAuth Client: Configuration → Simple OAuth → Clients → Add Client
  3. Assign scopes to roles
# Get token (Client Credentials)
curl -X POST https://site.com/oauth/token \
    -d "grant_type=client_credentials&client_id=CLIENT_ID&client_secret=CLIENT_SECRET&scope=editor"

# Request with Bearer token
curl https://site.com/jsonapi/node/article \
    -H "Authorization: Bearer ACCESS_TOKEN"

REST API: Custom Resources

// src/Plugin/rest/resource/ProductStockResource.php
namespace Drupal\mymodule\Plugin\rest\resource;

use Drupal\rest\Plugin\ResourceBase;
use Drupal\rest\ResourceResponse;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;

/**
 * @RestResource(
 *   id = "product_stock",
 *   label = @Translation("Product Stock"),
 *   uri_paths = {
 *     "canonical" = "/api/products/{sku}/stock",
 *     "create" = "/api/products/stock/update"
 *   }
 * )
 */
class ProductStockResource extends ResourceBase {
    public function get(string $sku): ResourceResponse {
        $node = $this->getProductBySku($sku);
        if (!$node) {
            throw new NotFoundHttpException("Product $sku not found");
        }

        $response = new ResourceResponse([
            'sku' => $sku,
            'stock' => (int) $node->get('field_stock_quantity')->value,
            'available' => (bool) $node->get('field_in_stock')->value,
        ]);
        $response->addCacheableDependency($node);
        return $response;
    }

    public function patch(array $data): ResourceResponse {
        $sku = $data['sku'] ?? throw new BadRequestHttpException('SKU required');
        $node = $this->getProductBySku($sku);
        $node->set('field_stock_quantity', $data['quantity']);
        $node->save();
        return new ResourceResponse(['updated' => true], 200);
    }
}

Enable resource: Configuration → Web Services → REST → enable product_stock.

Custom JSON:API Filter

// Add computed field to JSON:API response
use Drupal\jsonapi\ResourceType\ResourceTypeRepositoryInterface;

// Via hook_jsonapi_resource_type_field_alter
function mymodule_jsonapi_resource_type_field_alter(array &$fields, EntityTypeInterface $entity_type, string $bundle): void {
    if ($entity_type->id() === 'node' && $bundle === 'product') {
        $fields['price_with_discount'] = ResourceTypeField::toPublicName('price_with_discount');
    }
}

JSON:API Extras: Additional Configuration

composer require drupal/jsonapi_extras
drush en jsonapi_extras -y

JSON:API Extras allows:

  • Disable endpoints for specific content types
  • Change field names in response
  • Add computed fields
  • Configure API versioning

Response Caching

Drupal automatically caches JSON:API responses via Cache API with cache tags. When a node is updated, the cache for related requests is invalidated.

Add Varnish or Nginx FastCGI Cache before Drupal for maximum performance of public API endpoints.

Timeline

Basic JSON:API configuration with OAuth authentication — 2–3 days. Custom REST resources and JSON:API Extras — additional 2–3 days.