實作 PHP API & 留言板 SPA(上)


Posted by Nicolakacha on 2020-09-12

之前我們做了留言板是由 PHP 從資料庫拿資料並直接渲染出來,這次要來把留言板改造成一個 SPA 單頁式應用,並用 PHP 做出一個可以串接的 API。

什麼是單頁式應用?

從名詞上來解釋就是所有的功能動作都是在同一個頁面上完成的,不會切換到其他頁面,所以稱為單頁式應用。SPA 做到前後端分離,後端只負責和資料相關的部份,前端用 ajax 和後端互動拿到資料之後,再透過 JavaScript 來處理資料,決定資料要怎麼渲染到畫面上。

開始之前

開始之前的準備工作才是最重要的,我們先來想一下要做出什麼東西?需要哪些檔案做哪些事情?

要做出什麼東西?
要做出可以把資料存在資料庫的留言板,在留言板的網址後加上 ?SiteKey=Nicolas 就能連到 Nicolas 專屬的留言板,輸入 ?SiteKey=Jason 就能連到 Jason 的留言板。
這個留言板不需要登入功能,在留言的時候只有輸入暱稱和留言的欄位。

需要哪些檔案?
index.html style.css
我們會需要基本的 HTML 和 CSS 來打造留言板的架構和外觀。
script.js
把留言交給後端儲存,或是接收後端的留言資料並操控 DOM 把留言資料放到網頁上,都需要透過 JavaScript 發 Request 串接 API 來完成。
api_comments.php
這支 PHP 的功能是要從資料庫拿到留言資料,並把留言資料用 response 回傳交給 script.js。
add_comments_api.php
這支 PHP 要在新增留言的時候,把新留言寫進資料庫裡面,回傳的 response 是告訴我們存成功了還是失敗了
conn.php
需要一支 PHP 用來連線 MySQL 資料庫,此外還需要在資料庫建立好要存資料的 table,這部份我們原來的留言板就已經有做好了,所以不會細講。

不過,要從前端的頁面開始,還是要從後端的 PHP 開始啊?
一種做法是我們可以先寫後端的 PHP API,利用 POSTMAN 之後的工具測試 API 可以正常執行,在做出一個留言板頁面,用 script.js 來串接 API,把新增的留言存進去,並把留言渲染到網頁上。

後端 PHP 製作 API

api_comments.php
連線到後端的資料庫後,這支 PHP 的功能先看網址列有沒有 site_key,如果沒有,我們就回傳請輸入 site_key 的 response,如果有拿到 $_GET 的 site_key,我們就從後端拿對應的留言資料,並把全部的留言以 JSON 的格式回傳response 給前端的 script.js

怎麼建立回傳的 response 內容?
我們可以先想回傳的 response 要長什麼樣子,假設沒有拿到 site_key 的時候,我們想回傳一個 JSON 是這樣的:

{
    "ok": false,
    "message": "Please send site_key in url"
}

如果沒有拿到 site_key 我們就宣告一個 $json 陣列,利用 PHP 關聯陣列 (Associative array) 的方法,把 key 和 value 設定成 'ok' => false 和 'message' => 'Please send site_key in url',接著把這個陣列透過 json_encode($json) 轉換成 JSON 格式,存成 $response 這個變數,最後 echo 出來,代表傳 respsone 出去。
程式碼就會像這樣:

 if (empty($_GET['site_key'])) {
    $json = [
      'ok' => false, 
      'message' => 'Please send site_key in url'
    ];
    $response = json_encode($json);
    echo $response;
    die();
  }

如果有拿到 site_key,我們想把資料庫裡面該 site_key 對應的留言都拿出來並 response 回去,可以這麼寫:
先宣告一個陣列 $discusson,然後把每一筆資料都存成一個陣列,再把每一筆資料陣列都 push 進 $discussion 裡。
一樣宣告一個 $json 陣列,第一個陣列元素可以放接收成功的訊息 'ok' => true, 第二個陣列元素放我們剛才準備好的 $discussion,最後一樣把這個陣列透過 json_encode($json) 轉換成 JSON 格式,存成 $response 這個變數,最後 echo 出來,代表傳 respsone 出去。

$result = $stmt->get_result();
  $discussion = [];
  while ($row = $result->fetch_assoc()) {
    array_push($discussion, [
      'nickname' => $row['nickname'],
      'content' => $row['content'],
      'created_at' => $row['created_at'],
      'id' => $row['id']
    ]);
  }

  $json = [
    'ok' => true, 
    'discussion' => $discussion
  ];
  $response = json_encode($json);
  echo $response;

到這裡其實我們忘了處理連線資料庫出問題時的狀況,所以再做一種連線有問題的 response 情況

if(!$result) {
$json = [
  'ok' => false, 
  'message' => $conn->error
];
$response = json_encode($json);
echo $response;
die();
}

以下就是完整的 api_comments.php 程式碼,要特別注意的是,需要幫我們的 response 加入 header,以設定我們的內容格式,以及允許跨域的 Request,到這裡,我們讀取留言的 API 就完成啦!

<?php
  require_once('conn.php');
  header('Content-type:application/json;charset=utf-8');
  header('Access-Control-Allow-Origin: *');

  if (empty($_GET['site_key'])) {
    $json = [
      'ok' => false, 
      'message' => 'Please send site_key in url'
    ];
    $response = json_encode($json);
    echo $response;
    die();
  }
  $siteKey = $_GET['site_key'];

  $sql = "SELECT nickname, content, created_at, id FROM nicolakacha_discussion WHERE site_key =? ORDER BY id DESC";
  $stmt = $conn->prepare($sql);
  $stmt->bind_param('s', $siteKey);
  $result = $stmt->execute();
  if(!$result) {
    $json = [
      'ok' => false, 
      'message' => $conn->error
    ];
    $response = json_encode($json);
    echo $response;
    die();
  }

  $result = $stmt->get_result();
  $discussion = [];
  while ($row = $result->fetch_assoc()) {
    array_push($discussion, [
      'nickname' => $row['nickname'],
      'content' => $row['content'],
      'created_at' => $row['created_at'],
      'id' => $row['id']
    ]);
  }

  $json = [
    'ok' => true, 
    'discussion' => $discussion
  ];
  $response = json_encode($json);
  echo $response;
?>

可以透過 POSTMAN 測試看看是否正常運作:
有拿到 site_key 的 response 長這樣

沒有拿到 site_key 的 response 長這樣

看來沒問題惹,我們接著著手新增留言的 PHP API 吧。

add_comments_api.php
有了實作讀取留言 API 的經驗,再來做新增留言的 API 也很好上手。
首先先檢查是否有 POST 進來 site_key、暱稱和留言內容,如果沒有,我們的 response 就送一個請提醒輸入所有內容的訊息並結束程式:

 if (
    empty($_POST['site_key']) ||
    empty($_POST['nickname']) ||
    empty($_POST['content'])
    ) {
    $json = [
      'ok' => false, 
      'message' => 'Please input all fields'
    ];
    $response = json_encode($json);
    echo $response;
    die();
  }

如果要求的三個 POST 都有,我們就把資料存進去資料庫,如果存成功,就 response 一個會告訴 client 端成功的訊息,若存失敗,就 response 錯誤的訊息,於是完整的程式碼就長這樣:

<?php
  require_once('conn.php');
  header('Content-type:application/json;charset=utf-8');
  header('Access-Control-Allow-Origin: *');
  if (
    empty($_POST['site_key']) ||
    empty($_POST['nickname']) ||
    empty($_POST['content'])
    ) {
    $json = [
      'ok' => false, 
      'message' => 'Please input all fields'
    ];
    $response = json_encode($json);
    echo $response;
    die();
  }
  $siteKey = $_POST['site_key'];
  $nickname = $_POST['nickname'];
  $content = $_POST['content'];
  $created_at = date('Y-m-d h:i:s',time()+28800);
  $sql = "INSERT INTO nicolakacha_discussion(site_key, nickname, content) VALUES (?, ?, ?)";
  $stmt = $conn->prepare($sql);
  $stmt->bind_param('sss', $siteKey, $nickname, $content);
  $result = $stmt->execute();

  $json = $result ? [
    'ok' => true, 
    'message' => 'Add successfully',
    'created_at' => $created_at]
     : ['ok' => false, 'msg' => $conn->error];
  $response = json_encode($json);
  echo $response;
?>

同樣我們可以用 POSTMAN 來測試看看,試著新增一筆留言,如果 API 有正常運作,就會看到這個新增成功的 response 了:

以上就完成後端 API 的部份啦,前端的部份我們下篇文章再繼續~
下篇:實作 PHP API & 留言板 SPA(下)


#PHP #API #frontend







Related Posts

我很菜,所以只會用原生 JS 跟 CSS 寫「口罩地圖 」Ep.00

我很菜,所以只會用原生 JS 跟 CSS 寫「口罩地圖 」Ep.00

深入學習 lsd-slam - 5

深入學習 lsd-slam - 5

設計模式 7 Day 目錄

設計模式 7 Day 目錄


Comments