一月 16, 2022 | 後端和Drupal
【Drupal 9 教學】如何建立一個客製化REST API來接收前端資料
用Drupal Console 快速建立 POST Method
由於現在越來越多好用的前端框架與套件,可以更有效的處理跟使用者的互動與傳值,因此,用Drupal方便建立API的特性,可以直接建立一個API給前端使用。這篇文章主要將教我們如何用Drupal的API來接收前端POST過來的值。
執行步驟
- 建立REST RESOURCE
- 啟用REST RESOURCE
- 建立權限
- 針對POST進來的值進行寫入資料庫
- 測試
建立REST RESOURCE
這個是Drupal的REST API,我們要建立一個REST API來承接前端POST到後端的值
- 利用Drupal Console的指令 參考資料
$ drupal gprr
指令會利用互動的方式讓我們能夠順利建立完畢一個REST API,由於我們是要承接前端POST到後端的資料,所以我們會需要選擇POST的方式
- 查看是否Drupal Console有自動建立一個REST RESOURCE的檔案,在我們的模組之中
備註:
- 如果沒有客製化模組,就用以下指令建立
$ drupal gm
啟用REST RESOURCE
建立好了資料以後,會需要從Drupal的後台啟用這個REST API,可以通過以下路徑找到這個API/admin/config/services/rest
,若沒有這個路徑,則是需要安裝模組 RESTUI
找到剛建立的API,啟用他
API的支援方法,我們選用POST,然後接受的格式使用常用的JSON,認證方式則是選擇Cookies(代表是目前瀏覽網站的使用者)
啟用後的畫面
建立權限
由於每個API,Drupal可以設定誰可以使用,而我們這個API主要是給任何瀏覽這個網站的匿名使用者,所以權限要到角色的地方勾選
備註:
- 當然,如果你的網站是有會員系統的,同樣可以通過只有註冊會員才能使用API,來管控對應的行為
- 只要是設定,都要記得使用
drush cex -y
來匯出其相關設定 - 當權限已經建立完成,其實就可以用前端的
$.post
或$.ajax()
之類的函數來進行POST的測試,當然POST的路徑要以我們指令建立的路徑為主 - Drupal由於有很好的資安,所以有使用CSRF-TOKEN的方式來保護API
- 在目前沒有對撰寫任何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);
}
}
備註
- 預設的payload參數需要置換為data
結論
由於目前為了滿足客人更多畫面上的需求,Drupal往往已經從同時處理前端與後端,到變成純粹處理後端,而如何提供對應的API來提供前端的框架或是套件,變成非常重要的課題,Drupal到了D8之後,處理這個方面的議題,變成非常的簡單與容易,加上權限的控制,更能夠在資訊安全兼顧的情況下,讓網站變的更加彈性,是個非常好用的方法。