You are currently viewing RESTful API是什麼?3個RESTful API的設計原則與實踐方式

RESTful API是什麼?3個RESTful API的設計原則與實踐方式

在Web開發上我們經常聽過且用過RESTful API,是經常遇到的技術名詞,那麼RESTful API到底是什麼?以及為何要用RESTful API?
在本文中ㄚ建將介紹RESTful API是什麼?並建立一個簡單的RESTful API。

  • RESTful API 是什麼?
  • 為何要使用REST API?
  • RESTful API的概念是什麼?
  • 如何建立一個RESTful API

什麼是RESTful API?

在了解RESTful API之前讓我們先從基本的API的概念開始。

什麼是API?

讓我們先從下面的影片來了解API的概念。

API全名為Application Programming Interface(應用程式介面),它定義了軟體之間通訊時需要遵循的規則。我們使用的網站或是app就如同影片中譬喻的餐廳,API扮演著應用程式之簡彼此溝通的橋樑,如同影片中送餐的服務生負責傳遞(轉達)我們的行為/點餐需求,傳遞需求並建立連結。而我們不需要知道其(api)背後的運作方式。

也就是當我們需要某些功能例如開發一個提供地圖定位的服務,可以將我們的需求(點餐行為)透過API(服務生)傳遞給其他開發人員或是第3方提供的API服務(廚房),例如Google Map API,整個過程我們只需要知道3件事:

  1. 發送API之前需要提供什麼資料?
  2. 成功時API會回應什麼?
  3. 失敗時API會回應什麼?

因此我們不必了解Google Map API背後的邏輯機制,只需要依照開發人員或是提供API服務的第三方,例如Google,提供的規格文件來使用即可。如此一來在開發上省下了自行開發並維護API的難題,而我們只需要專注於處理與維護由API取得結果即可!
對API有了概念之後,接下來便可以進入本文的主軸RESTful API。

什麼是REST?

REST的全名為Representational State Transfer( 表現層狀態轉移),REST並不是獨特的技術規範,而是一種軟體架構的風格。
遵循REST架構所設計的API便被稱為REST API,而實作REST架構的Web服務則稱為RESTful Web服務。在術語的稱呼上RESTful API與REST API可以相互交換使用。

在實務上並非所有前端UI都會與HTML頁面一起工作,或是透過Server Side Render來產生畫面。我們可以從下列3種實務上應用來看:

  • 行動app。
  • SPA網站。
  • 其他服務API:如Google Map、中央氣象局等其他網站的Open API。

上面的應用例子之間的共同點便是僅Client與Server透過資料進行溝通,我們不希望由Server傳遞HTML的程式來構建頁面,Client只是需要Server提供的資料,這便是使用API的核心思想。為了在開發上增進API的可視性與跨平台可移植性,透過REST對API的運作施加設計規範便是RESTful API。

如何設計RESTful API?

在開始設計RESTful API之前,首先我們需要先從RESTful-Triangle的概念來了解RESTful API三個重要概念。

RESTful-Triangle

RESTful-Triangle
RESTful-Triangle
  • Nouns 名詞:用來定義傳輸資源的URL。
  • Verbs 動詞:對Nouns名詞的操作方式,也就是HTTP Methods。
  • Content Types 資源呈現方式:資源的呈現方式有許多種,最常用的便是JSON,相較於其他方式JSON更為簡潔,且容易轉換成JavaScript處理。

以上3點的組合也就是API端點(API Endpoints),它們構成了RESTful API的定義。

HTTP Methods (HTTP Verbs)

在定義了API的URL之後,我們便必須告知Server需要對資料做什麼?方法便是由HTTP Methods完成,下面介紹5種常用的HTTP Methods:

  • GET:從Server取得資源或是狀態。
  • POST:將資源發佈到Server,例如新增一筆資料。
  • PUT:在Server上新增或修改指定資源。
  • PATCH:更新Server上現有資源的一部分。
  • DELETE:刪除Server的資源。

REST 架構風格的原則

在RESTful-Triangle我們理解了RESTful API的概念,以下的REST架構原則定義了一些設計RESTful API的核心原則:

  1. 統一介面:具有HTTP Methods、route與明確定義的請求與響應資料結構的組合。
  2. 無狀態:Server與Client不儲存連接歷史,每個請求都是獨立的。
  3. 可快取性:RESTful API可以透過快取來改善Server的回應時間。
  4. 客戶端服務器分離:Client不關心持久化的資料儲存。
  5. 分層系統:Server可以將請求轉發到其他API。Client可以連線到其他授權的API,而仍然可以接收來自Server的回應。
  6. 隨需編碼:可執行的程式碼可從Server傳輸到Client,以臨時擴展或自訂Client功能。

這6項原則之中,其中統一介面無狀態較為核心。

統一介面:簡單定義了我們設計RESTful API時應該具有明確定義的API端點(API Endpoints),也就是上述RESTful-Triangle的3個概念。這讓使用者了解API需要哪些資料,以及返回那些資料。

無狀態:這邊要注意一點!由於HTTP無狀態特性,我們設計API時,Client與Server是完全分離的,所以不共享任何連線歷史。意味著狀態由Client自行保存,向Server請求時附上。Server不會保存Client的狀態資訊,因此是無狀態的。這樣的設計讓Server每次能完全理解並滿足請求。

建立一個RESTful API

現在我們已經知道設計RESTful API所需的概念以及原則,接下來一起來實際設計一個RESTful API吧!

事前準備

這邊將透過nodejs搭配express建立我們的RESTful API。

安裝方式可以可以參閱nodejs官網

接著開啟vscode,在專案的資料夾內開啟終端機(Terminal)輸入下列指令,建立所需的環境。

npm init
npm install --save express
npm install --save-dev nodemon
npm install --save body-parser

建立環境後,首先修改package.json的設定。

在下圖的scripts位置加入下面提供的程式碼。

packageJson設定
package.json設定
//package.json
"start": "nodemon app.js"

如此一來,每當修改程式後,我們便不需要再手動重啟Server。

接下來在根目錄新增routes、controllers資料夾以及app.js。
routes是用來存放api的路由設定,controllers存放負責控制api的檔案。
然後各別資料夾新增helloApi.js。

整個專案的檔案配置如下圖:

資料夾檔案配置
資料夾檔案配置

下面是各個檔案的程式碼:

app.js:負責管理我們API的路由helloApi以及啟動Server,這邊設定是port 8080,有需要可以自行更改。

// app.js
const express = require('express');
const bodyParser = require('body-parser');

const helloApiRoutes = require('./routes/helloApi');

const app = express();
app.use(bodyParser.json());

// 配置helloApi路由
app.use('/helloApi', helloApiRoutes);

// port8080
app.listen(8080);

constrollers的helloApi.js負責管理api回應的內容。
這邊設定了post與get回應的內容。

// constrollers/helloApi.js
// api 回應的內容
exports.getPosts = (req, res, next) => {
    res.status(200).json({
        post: [{
            title: "First Post!",
            content: "This is the first post!"
        }]
    });
};
//
exports.createPost = (req, res, next) => {
    const title = req.body.title;
    const content = req.body.content;
    // create post in db
    res.status(201).json({
        message: "Post create successfully!",
        post: {
            id: new Date().toISOString(),
            title: title,
            content: content,
        }
    })
};

routes的helloApi.js負責定義api的get文章的路由。

// routes/helloApi.js
const express = require('express');

const helloApi_Controller = require('../controllers/helloApi');
const router = express.Router();
// GET helloApi/posts
router.get('/posts', helloApi_Controller.getPosts);

// POST /helloApi/post
router.post('/post', helloApi_Controller.createPost);
module.exports = router;

接著在終端機(Terminal)執行npm start啟動Server。

測試我們的API?

首先,來看API的get方法。
打開瀏覽器在localhost:8080輸入API的路由helloApi/post,下圖便是成功取得API回應的結果。

api執行結果
api執行結果

接下來測試API的post方法。
要測試post方法,便需要由前端發送API請求給Server,那麼該有哪些工具可以協助我們?

這邊阿建提供2種方式來測試API:

第一種:Postman,這是一套免費且方便的工具,你可以到Postman官網免費下載安裝。

第二種:codepen,這是可以線上編寫前端的網站,可以用來模擬前端的應用,還可以分享你的成果!

這裡阿建使用第二種方式。原因是,透過codepen我們可以快速建立前端的頁面,並讓我們模擬第三方使用者的操作情形。

這裡阿建提供codepen的範例,在啟動Server後不妨試試看!

See the Pen
restapi test
by chieninker (@chieninker)
on CodePen.

首先打開控制台的console,接著點擊Get Posts按鍵,這時Server非但沒有正確的回應,反而出現一段錯誤!

CORS 錯誤
CORS 錯誤

這便是常見的CORS(跨來源資源共用)錯誤。至於錯誤究竟出在哪裡?以及如何解決?
接下來讓阿建帶你一步步處理這個錯誤。

CORS是什麼?

跨來源資源共用(CORS)全名為Cross-Origin Resource Sharing,是一種,它是如何產生?

先看下面這張圖:

CORS Error

在默認的情況下,瀏覽器不允許我們跨站取得資源,也就是當Client與Server在同一網域時,如上圖的A部分,彼此可以相互發送請求與回應。但是當Client與Server處於不同網域便會產生CORS錯誤,如上圖的B部分。其中原因是瀏覽器背後的安全機制所致,所以我們無法跨網域、跨伺服器與跨源共享資源。

然而我們設計API便是希望將Server的資料為各種不同的Client提供服務,這個機制會對API的開發造成問題。
為了解決CORS錯誤,我們需要告訴瀏覽器(這邊是CodePen)讓它可以接受由我們的Server發送的回應。

解決方式

為了解決問題,我們必須在Server更改一些地方。回到app.js,我們需要在這裡設定API的Header。

const express = require('express');
const bodyParser = require('body-parser');

const helloApiRoutes = require('./routes/helloApi');

const app = express();

app.use(bodyParser.json());

// CORS error
app.use((req, res, next) => {
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST');
    res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
    next();
})
app.use('/helloApi', helloApiRoutes);
app.listen(8080);
  • Access-Control-Allow-Origin:設定能訪問Server的網域,‘*’表示允許任何網域跨站存取資源
  • Access-Control-Allow-Methods:允許的HTTP Methods
  • Access-Control-Allow-Headers:允許的請求標頭,這邊設定Client可以發送在標頭中包含額外授權資料的請求。

為API加入Header後,接著回到CodePen,並重新發送我們的請求,可以看到Server回應的訊息了!

正確取得回應
正確取得回應-GET
Post的回應
正確取得回應-Post

參考資料

NodeJS – The Complete Guide
MDN-CORS
MDN-Access-Control-Allow-Headers
AWS-什麼是 RESTful API?
RESTful API 設計準則與實務經驗

發佈留言