POSTMAN – Pre-request script

POSTMAN 除了可以發送 request 到 server 之外,也有提供 pre-request script 的功能,讓我們可以撰寫 script 來進行一連串的測試。

舉個例子,我們有三支 API,邏輯為 名稱(Request body)【Response body】:

  • 登入(帳號、密碼)【Token】
  • 取得使用者的消費紀錄列表(Token)【Array<Receipt ID>】
  • 取得單筆消費紀錄(Receipt ID)【Receipt】

在沒有撰寫 pre-request 之前若要取得 Receipt 的話,我們得要先呼叫 登入,接著手動複製 Token 到 取得使用者的消費紀錄列表 的 request body 裡頭,然後再複製⋯⋯(你們應該懂)

這邊就來教教如何先寫好 script,之後只要按最後你想得到的那支 API 就行了!

let account = 'account'
let password = 'password'
let index = 0

pm.sendRequest({
    url: 'https://Archie.tw/login?account=' + account + '&password=' + password,
    method: 'get'
}, function(err, response) {
    let token = response.json().token;
    pm.sendRequest({
        url: 'https://Archie.tw/getReceiptList?token=' + token,
        method: 'get'
    }, function(err, response) {
        pm.environment.set("receiptIdentifier", response.receiptIdentifier);
    });
});

接著在 Params / Body 那邊就可以使用剛剛所定義的環境變數({{receiptIdentifier}})了!

然後請不要真的打範例的 url,是不會有東西回給你的(真的)。

Firebase Database REST API

這篇主要的內容會是簡單地記錄一下 Firebase Database RESTful API

所提供的相關內容和使用方式。

Firebase Database

Firebase database 的儲存資料方式是屬於 NoSQL 的方式,

利用一組 key 配對一組 value 的模式來建構資料庫;

而在 Database 的介面中,我們可以清楚地看到資料是以 JSON 的格式呈現。

在 iOS 開發的過程中,如果要使用 Firebase 的相關內容,

可以使用官方所提供的 Firebase iOS SDK

或是在使用 Python 開發的時候,我會選擇使用官方推薦的 Pyrebase

那若你目前的開發方式沒有相對應的 SDK 或是 third party 可以使用的話呢?

那麼你就只能一起用 REST API 來完成要做的事情了!

REST API

Firebase 提供了五種 Http method

  • GET
  • PUT
  • POST
  • PATCH
  • DELETE

其中 GET 和 DELETE 就沒什麼特別好說的,你就是取得一個 JSON 或是刪除一個。

PUT

PUT 就和平常使用 PUT 的方式一樣,

它會把整個 JSON 覆蓋成你目前丟上去的 JSON。

POST

POST 的話就有些不一樣,當你 POST 一個資料到某個 JSON 的時候,

它會自行建立一組 key 並回傳 name 回來。

而你所丟的資料會是那組 key 所對應的 value,

所以簡單來說 POST 就是在做新增物件時使用,且 ID 是由它所建立的。

PATCH

PATCH 則是負責更新內容,它會先找到匹配的 key,再更新其 value;

若沒有找到相對應的 key 的話,則會建立一筆新的 key-value。

如果有其中一個無法使用呢?

若遇到你所使用的開發語言或是瀏覽器等等,無法使用其中一項 method 時;

舉個例子,DELETE 無法使用的話,Firebase 有提供你覆寫 method 的功能,

method 使用 POST,而在 header 加上:

X-HTTP-Method-Override: DELETE

便可以等同於上述所說的 DELETE。

或是加在 url 裡頭也可以:

https://%5BPROJECT_ID%5D.firebaseio/%5BJSON_NAME%5D.json?x-http-method-override=DELETE

 

Firebase ETag

Firebase 也有支援 ETag,

在 header 上加上 X-Firebase-ETag: true,它便會在回傳的 headers 中加上

Access-Control-Expose-Headers = ETag

ETag = kmHkuKx9sCx742tosJOV4oH+JBQ=

而我們可以下一次的 request 中,在 header 放上 if-match:[ETAG_VALUE]

伺服器端便會驗證是否可以執行這次的要求;

若最後一次的 ETag 和 if-match 的值相符的話,Firebase 便會回傳 412 Precondition failed。

而 ETag 相關的資訊可以看這邊

 

最後

整理完這些資訊後,就可以著手寫一些 database 的存取方法到 Vapor 的專案了!

Vapor

Vapor

在 Swift 開源之後,開發者們便開始將這語言往更多層面去發展,而 web app 便是其中一項。

Vapor 是一款以 Swift 作為主要語言的 Server 建構服務,讓我們可以透過它來開發 Web 相關的應用;

對於 iOS 開發人員而言,Swift 可以用來開發 web app 是一件有趣的事情,

其代表著我們可以使用同一個語言來開發一個產品,從 server 到 client。

安裝方式

不同於在安裝 iOS 第三方套件的流程,Vapor 需要透過 terminal 來安裝相關內容:

首先,得先安裝 Vapor 的 CLI

curl -sL toolbox.qutheory.io | sh

安裝完之後,便可以在 terminal 底下使用 vapor 的指令。

建立新專案

我們可以透過下方的指令,來建立一個新專案:

vapor new ProjectName

其中第三方套件的管理方式,是使用 Swift Package Manager

所以我們會在目錄下看到一個 Package.swift 和 Package.pins

這方面倒是有些像 CocoaPods 所使用的 Podfile 的概念。

使用 Xcode 開發

有了專案後,你可以選擇直接打開 main.swift 來進行開發,

但如果比較喜歡使用 Xcode 開啟一個專案,而非單一檔案,

則可以透過下方指令才建立 .project。

vapor xcode

這樣系統就會幫我們產生 .project 檔,開發起來就和原本寫 iOS 差不多了。

Server 的相關設定

Vapor 的 server 相關設定會放置在 Config 的資料夾底下,

其中包含五個 .json 檔案:

  • app.json
  • crypto.json
  • droplet.json
  • fluent.json
  • server.json

像是我們可以在 server.json 裡頭看到 host、port 的相關內容。

Build & Run

若你是開啟 Xcode 專案的方式,那麼 build 和 run 的方式就和以往開發 iOS 的方式一樣;

但若是沒有建立 .project 的話,也可以透過 vapor build 以及 run 的方式,就是在目錄下執行:

vapor build && vapor run

Droplet

在看到 Vapor 的 icon 之後,不難想像為何其主要的核心物件名稱為 droplet。

在初始時,main.swift 會有基本的 demo code,

我們可以直接在 try drop.setup() 下方加入一些內容。

這樣便會在 0.0.0.0:8080/ 時,得到 Hello World!

而也可以透過路徑來帶入參數,像是 0.0.0.0:8080/name/Archie 的寫法:

當連過去時,便會顯示 Hello Archie!

Views

Vapor 將 Views 放置在 /Resources/Views 裡頭,並可以使用 drop.view(“檔案名稱") 的方式回傳畫面:

以上便是 Vapor 的一些基本的簡單介紹,有興趣的人可以一起研究研究!

JSON Web Token

JWT

JWT( JSON Web Token)和 iOS 比較有相關聯的地方,

便是在於 APNs p8 是使用 JWT 格式作為傳遞;

而有關於 JWT 的相關資料,可以參考 [這個網站](https://jwt.io/introduction/)。

以之前所提到的 [APNs](https://www.archie.tw/apns) 來說,是由三個部分所組成:

  1. Header
  2. Payload
  3. Verify signature

Header

在 APNs 裡頭,需要包含這兩者

  • alg:所使用的加密方式(algorithm),p8 是使用 ES256 作為加密方式
  • kid:鑰匙的 ID(key identifier)

例如:

alg: ES256

kid: 12345678

Payload

  • iss:所發送的人(issuer),這邊為開發者的 Team ID
  • iat:所發送的時間(issued at)

Verify signature

這邊便是將上述兩者,分別做 base 64 加密後輸出成字串,再加上 p8 的 key,

一起做 ES256 加密後的結果,所以大概長這樣:

{header base 64 encode}.{payload base 64 encode}.{ES256 hash[(header base 64 encode).(payload base 64 encode),key]}

Swift 版本的 APNs

這幾天便是在研究如何在 Swift 中,實做推播的功能,目前卡在內建的加密方式是 HMAC 的為主,

並沒有 ECDSA p-256 的方式(ES256 = ECDSA p-256 加上 SHA 256),

故加密那段仍未能完成。

徵求

對 ES256 有研究的大大,分享一下如何在 Swift 上實作 ES256 加密!

APNs

APNs( Apple Push Notification service

相信有在開發 iOS app 的開發者,對於這個詞應該都不會太陌生;

簡單來說,它就是推播的功能。

而推播其實有分成兩種:

  1. Local notification
  2. Remote notification

這兩者的差異就如同名字的一般,前者是本地的通知,後者為遠端的通知。

Local notification

本地推播在 iOS 10 以後,可以參考 UserNotifications 這個 framework。

這邊附上以區域範圍為觸發條件的推播寫法:

而鬧鐘那種概念的,或是遊戲提醒(例如遊戲的愛心已經回滿了,趕快回來玩哦!),

這種以時間作為觸發條件的,則是設定 notification.fireDate,給它一個 Date 便會在那時候觸發。

Remote notification

遠端的推播則是如同聊天軟體常常收到的那種推播(OOO傳送貼圖給您!),

AppDelegate.swift 註冊那些的就不寫在這了~

如果是在公司上班或者和後端合作,寫完註冊推播及回傳 deviceToken 和收到之後要幹嘛的動作,

通常就不會碰到「該如何打推播給 App」的問題,因為 iOS 只需要知道收到該怎辦XD

但總會有需要自己打推播測試、或是開發自己 app  的時候,

這邊就來談談 iOS 開發者該怎麼做!

APNs key

以往我們在產生 APNs key 的時候,是會得到一組有期限的 .p12 檔案,

其中不同的 bundle identifier 會配對到不同的 .p12 檔案;

這是一件蠻麻煩的事情,我們需要管理不同 App 的 APNs key,

上架 20 個有推播功能的 app,就需要維護 20 組 .p12 檔案。

有沒有比較方便的做法?

答案是,有!

如果你是看完這篇文章,才開始接觸推播的話,

那你應該已經找不太到 .p12 要去哪裡產生了!

前陣子是 .p12 和新的 .p8 同時共存在 Apple Developer 的頁面,

而目前畫面則長這個樣子:

在產生 keys 的頁面,我們可以看到只剩下「One key is used for all of your apps.」這種的(.p8),

也就是說,只需要一把 key 便可以打給你所有開發的 app,且它並不會過期!

產生完 key 之後,只有在當下可以下載 .p8 的檔案;

若你當下沒下載,就按完成的話,之後點開則會發現 Download 的按鈕是灰色不可按的,

所以需要好好保存,別把它搞丟了,否則只能夠重新產生一把新的來替換。

接下來?

有了 .p8 檔案之後,我是用 Python 來實作打推播的動作,附上我的檔案

  1. apns_key_id = xxxxxxxxxx(你剛剛下載下來的 .p8 檔名)
  2. apns_key_name = ‘AuthKey_xxxxxxxxxx.p8’
  3. team_id = 你的 developer team id
  4. bundle_id = 推播要送到哪個 bundle id

建置 Python 環境

這邊會需要安裝一些 python 的套件:

可以下載 requirements.txt 放到和 .p8 及剛剛 .py 的同個資料夾,並執行

pip install -r requirements.txt

便會將所需要的套件下載安裝;

如果沒有安裝 pip⋯⋯建議可以自行先去 Google 一下XDD

萬事俱備後

把上述的檔案更改好後,和 .p8 放到同一個資料夾,接著開啟 terminal 執行 python。

  1. Test Title:推播的標題
  2. Test Body:推播的內容
  3. device token:要收到推播的裝置 token
  4. False:我最後一個參數是來控制要打給 production server 還是 development server

Python 和 Swift 看起來有點類似,所以應該不難看懂 APNs.py 是在幹嘛~

有問題可以留言給我,或是留在 gist 上!

 

更新:

我將文中內的內容整理至 Github 上,有興趣的人也可以直接去那 clone 下來研究。

 

最後

如果這篇文章對你有一點點幫助的話,可以幫我點個廣告來維持這網站的伺服器月費,

或是在相關的 gist 上給個 Star 鼓勵鼓勵!

502 Bad Gateway Error with nginx

源頭

在攥寫「七天學會設計模式 – Singleton」時,發生了點小狀況。

我點擊 WordPress 的「全部文章」時,顯示 502 Bad Gateway 的錯誤訊息;

由於點下去後不久(一、兩秒內)就跳轉出錯誤,故猜測不是 timeout 的關係,

便開始了一段 debug 的故事⋯⋯

環境

我是使用 WordPress(不是重點)的框架,並架設在 Vultr 的主機上;

主機的主要規格為 CPU 1 vCore、RAM 1024 MB、25 GB SSD。

 

原因

透過 nginx 的 error log(cat /var/log/nginx/wordpress_https_error.log)

發現關鍵字:

upstream sent too big header while reading response header from upstream

拿去餵狗的結果是,需要調整 nginx.conf(vim /etc/nginx/nginx.conf),

加上

來調整 buffer size,來避免資源不足直接捨棄的情況(502)。

由於 5 塊美金的方案,Vultr 僅提供 1024 MB 的記憶體大小,但它有 25 GB 的 SSD!

故可以透過 Swap 的方式,用硬碟換取記憶體的效能。

依序輸入完後,可以輸入「free」來看 swap 是否有使用相對應的 size 了!

便可以解決 nginx 因資源不足所產生的 502 Bad Gateway error!