logo

额外区块类型 (EBT) - 全新的布局构建器体验❗

额外区块类型 (EBT) - 样式化、可定制的区块类型:幻灯片、标签页、卡片、手风琴等更多类型。内置背景、DOM Box、JavaScript 插件的设置。立即体验布局构建的未来。

演示 EBT 模块 下载 EBT 模块

❗额外段落类型 (EPT) - 全新的 Paragraphs 体验

额外段落类型 (EPT) - 类似的基于 Paragraph 的模块集合。

演示 EPT 模块 滚动

滚动

创建新资源(POST)

04/09/2025, by Ivan

此页面展示了 JSON:API 模块 的各种 POST 请求示例。

POST 请求用于创建新资源。如果需要修改资源,请使用 PATCH。

JSON:API 规范(因此 JSON:API 模块)仅支持每个 POST 请求创建一个资源。对于 Drupal,这意味着无法(仅使用该模块)在一个请求中创建多个实体。如果你想在创建父实体的同时创建被引用的实体,就需要这种功能。虽然 JSON:API 不支持此行为,但像 Subrequests 这样的模块可以帮助实现。

启用创建操作

访问 /admin/config/services/jsonapi
并勾选 “接受所有 JSON:API 创建、读取、更新和删除操作” 选项。

Create, Read, Update, Delete methods
启用 创建、读取、更新、删除 操作

认证

通常 POST 请求需要某种形式的认证。以下示例均使用基本认证(Basic Authentication),即使用具有创建相应内容权限的现有网站用户的用户名和密码。

启用 HTTP Basic Authentication (basic_auth) 模块,为 API 用户(及角色)设置权限,并在请求头的 'Authorization' 中设置编码后的用户名和密码。

此页面上的示例请求头需要一个用户名为 'api'、密码为 'api' 的 Drupal 用户。

请求头

以下请求头在所有 POST 请求中都是必须的,以确保 JSON:API 请求和响应的正确性。

  • Accept: application/vnd.api+json
  • Content-Type: application/vnd.api+json

以下请求头在示例中需要使用:

  • Authorization: Basic YXBpOmFwaQ==

Curl

假设你的数据保存在 payload.json 文件中。

curl \
    --user api:api \
    --header 'Accept: application/vnd.api+json' \
    --header 'Content-type: application/vnd.api+json' \
    --request POST http://drupal.d8/jsonapi/node/article \
    --data-binary @payload.json

基本 POST 请求

URL: http://example.com/jsonapi/node/article

请求体

{
  "data": {
    "type": "node--article",
    "attributes": {
      "title": "我的自定义标题",
      "body": {
        "value": "自定义内容",
        "format": "plain_text"
      }
    }
  }
}

响应

HTTP 201 (Created) 响应。响应体包含已创建实体的 JsonApi 响应。

带关系的 POST 请求

URL: http://example.com/jsonapi/node/article

实体引用字段必须作为 relationships 设置,而不是 attributes。如果你未这样做,将会看到错误信息 “The following relationship fields were provided as attributes”,并附带有问题的字段列表。

id 键必须包含实体的UUID,而不是 ID;例如:faba301b-bdf5-4658-abc1-e173b815984f

请求体

{
  "data": {
    "type": "node--article",
    "attributes": {
      "title": "管理员创建的文章",
      "body": {
        "value": "自定义内容",
        "format": "plain_text"
      }
    },
    "relationships": {
      "uid": {
        "data": {
          "type": "user--user",
          "id": "{{用户1的UUID}}"
        }
      },
      "field_taxonomy_term_reference": {
        "data": {
          "type": "taxonomy_term--{{bundle}}",
          "id": "{{术语的UUID}}"
        }
      }
    }
  }
}

响应

HTTP 201 (Created) 响应。响应体包含已创建实体的 JsonApi 响应。

使用 REST API 的 POST 方法

首先创建一个带有 REST 资源的自定义模块,并通过 /admin/config/services/rest 启用。

<?php

namespace Drupal\rest_examples\Plugin\rest\resource;

use Drupal\node\Entity\Node;
use Drupal\rest\Plugin\ResourceBase;
use Drupal\rest\ResourceResponse;
use Drupal\Core\Session\AccountProxyInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;

/**
 * 提供一个用于创建节点的资源。
 *
 * @RestResource(
 *   id = "rest_resource_post_example",
 *   label = @Translation("Rest Resource Post Example"),
 *   uri_paths = {
 *     "create" = "/rest/api/post/node-create"
 *   }
 * )
 */
class RestResourcePostExample extends ResourceBase {

  use StringTranslationTrait;

  /**
   * 当前用户实例。
   *
   * @var \Drupal\Core\Session\AccountProxyInterface
   */
  protected $currentUser;

  /**
   * 构造函数。
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, array $serializer_formats, LoggerInterface $logger, AccountProxyInterface $current_user) {

    parent::__construct($configuration, $plugin_id, $plugin_definition, $serializer_formats, $logger);

    $this->currentUser = $current_user;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->getParameter('serializer.formats'),
      $container->get('logger.factory')->get('rest_examples'),
      $container->get('current_user')
    );
  }

  /**
   * 响应 POST 请求。
   *
   * 创建一个新的节点。
   */
  public function post($data) {

    // 验证用户是否有权限。
    if (!$this->currentUser->hasPermission('administer site content')) {
      throw new AccessDeniedHttpException('访问被拒绝。');
    }

    foreach ($data as $key => $value) {

      $node = Node::create(
        [
          'type' => $value['nodetype'],
          'title' => $value['title'],
          'body' => [
            'summary' => '',
            'value' => $value['body'],
            'format' => 'full_html',
          ],
        ]
      );

      $node->enforceIsNew();
      $node->save();

      $this->logger->notice($this->t("Node with nid @nid saved!\n", ['@nid' => $node->id()]));

      $nodes[] = $node->id();

    }

    $message = $this->t("新节点已创建,nid : @message", ['@message' => implode(",", $nodes)]);

    return new ResourceResponse($message, 200);

  }

}

用于创建节点的 JSON 示例数据:

[
    {
        "nodetype": "article",
        "title": "培训",
        "body": "Cum sociis natoque penatibus..."
    },
    {
        "nodetype": "page",
        "title": "团队建设",
        "body": "Integer tincidunt ante vel ipsum..."
    },
    {
        "nodetype": "article",
        "title": "服务",
        "body": "Proin interdum mauris non ligula..."
    },
    {
        "nodetype": "page",
        "title": "产品管理",
        "body": "Cras mi pede, malesuada in..."
    },
    {
        "nodetype": "article",
        "title": "业务发展",
        "body": "Nullam porttitor lacus at turpis..."
    }
]

发送 POST 请求的 Curl 命令:

curl \
    --user uname:password \
    --header 'Accept: application/json' \
    --header 'Content-type: application/json' \
    --request POST http://example.com/rest/api/post/node-create \
    --data-binary @post_data.json

文章来源:Drupal 文档