一月 16, 2022 | 後端和Drupal

【Drupal 9 教學】如何建立一個客製化REST API來接收前端資料

用Drupal Console 快速建立 POST Method
由於現在越來越多好用的前端框架與套件,可以更有效的處理跟使用者的互動與傳值,因此,用Drupal方便建立API的特性,可以直接建立一個API給前端使用。這篇文章主要將教我們如何用Drupal的API來接收前端POST過來的值。

執行步驟

  1. 建立REST RESOURCE
  2. 啟用REST RESOURCE
  3. 建立權限
  4. 針對POST進來的值進行寫入資料庫
  5. 測試

建立REST RESOURCE

這個是Drupal的REST API,我們要建立一個REST API來承接前端POST到後端的值

  1. 利用Drupal Console的指令 參考資料
$ drupal gprr

指令會利用互動的方式讓我們能夠順利建立完畢一個REST API,由於我們是要承接前端POST到後端的資料,所以我們會需要選擇POST的方式

  1. 查看是否Drupal Console有自動建立一個REST RESOURCE的檔案,在我們的模組之中

備註:

  1. 如果沒有客製化模組,就用以下指令建立
$ drupal gm

啟用REST RESOURCE

建立好了資料以後,會需要從Drupal的後台啟用這個REST API,可以通過以下路徑找到這個API/admin/config/services/rest ,若沒有這個路徑,則是需要安裝模組 RESTUI

  1. 找到剛建立的API,啟用他

  2. API的支援方法,我們選用POST,然後接受的格式使用常用的JSON,認證方式則是選擇Cookies(代表是目前瀏覽網站的使用者)

  3. 啟用後的畫面

建立權限

由於每個API,Drupal可以設定誰可以使用,而我們這個API主要是給任何瀏覽這個網站的匿名使用者,所以權限要到角色的地方勾選

備註:

  1. 當然,如果你的網站是有會員系統的,同樣可以通過只有註冊會員才能使用API,來管控對應的行為
  2. 只要是設定,都要記得使用 drush cex -y 來匯出其相關設定
  3. 當權限已經建立完成,其實就可以用前端的$.post$.ajax()之類的函數來進行POST的測試,當然POST的路徑要以我們指令建立的路徑為主
  4. Drupal由於有很好的資安,所以有使用CSRF-TOKEN的方式來保護API
  5. 在目前沒有對撰寫任何API內容的情況下,REST 會將POST的結果原封不動的回傳回去

範例

axios.get('/session/token?nocache=' + Math.random()).then(function (response) {
    var csrf = response.data;
    axios.post('/api/vote?_format=json', dataJSON, {
      headers: {
        "X-CSRF-Token": csrf
      },
    }).then(response => {
      var reS = response.data.status;
      var data =response.data;
    })
  });

針對POST進來的值進行寫入資料庫

可以拿到前端POST到後端的值之後,就可以來進行API的後續開發,將前端拿到的結果,寫入Webform Submission裡面。 這裡會需要用到WebformSubmission的物件,來協助我們將前端的值寫入到資料庫。

VoteResetResource.php 顯示接受到前端POST過來的值後,進行判斷並且寫入到後端資料庫

<?php

namespace Drupal\game_custom\Plugin\rest\resource;

use Drupal\rest\ModifiedResourceResponse;
use Drupal\rest\Plugin\ResourceBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Webform\Entity\WebformSubmission;

/**
 * Provides a resource to get view modes by entity and bundle.
 *
 * @RestResource(
 *   id = "vote_rest_resource",
 *   label = @Translation("Vote rest resource"),
 *   uri_paths = {
 *     "create" = "/api/vote"
 *   }
 * )
 */
class VoteRestResource extends ResourceBase {

  /**
   * A current user instance.
   *
   * @var \Drupal\Core\Session\AccountProxyInterface
   */
  protected $currentUser;

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    $instance = parent::create($container, $configuration, $plugin_id, $plugin_definition);
    $instance->logger = $container->get('logger.factory')->get('game_custom');
    $instance->currentUser = $container->get('current_user');
    return $instance;
  }

  /**
   * Responds to POST requests.
   *
   * @param string $data
   *
   * @return \Drupal\rest\ModifiedResourceResponse
   *   The HTTP response object.
   *
   * @throws \Symfony\Component\HttpKernel\Exception\HttpException
   *   Throws exception expected.
   */
  public function post($data) {

    try {
      $name = $data['name'] ?? "";
      if (!$name) {
        throw new \Exception("沒有姓名");
      }

      // 開始寫入資料庫.
      $values = [
        'webform_id' => 'game',
        'data' => [
          'name' => $name,
          'usource' => $data['usource'] ?? "",
          'ucontent' => $data['ucontent'] ?? "",
          'umedium' => $data['umedium'] ?? "",
          'ucampaign' => $data['ucampaign'] ?? "",
        ],
      ];
      /** @var \Drupal\webform\WebformSubmissionInterface $webform_submission */
      $webform_submission = WebformSubmission::create($values);
      $webform_submission->save();
      $rtn = [
        'status' => 'succeed',
      ];
    }
    catch (\Exception $e) {
      return new ModifiedResourceResponse([
        'message' => $e->getMessage(),
      ], 400);
    }
    return new ModifiedResourceResponse($rtn, 200);
  }

}


備註

  1. 預設的payload參數需要置換為data

結論

由於目前為了滿足客人更多畫面上的需求,Drupal往往已經從同時處理前端與後端,到變成純粹處理後端,而如何提供對應的API來提供前端的框架或是套件,變成非常重要的課題,Drupal到了D8之後,處理這個方面的議題,變成非常的簡單與容易,加上權限的控制,更能夠在資訊安全兼顧的情況下,讓網站變的更加彈性,是個非常好用的方法。

參考資料

  1. https://www.drupal.org/docs/8/core/modules/rest/1-getting-started-rest-configuration-rest-request-fundamentals