[練習] 後端推播 sample 的 Spec

使用者 API

新增使用者

POST /api/user

{
    "username": <string>,
    "password": <string>
}

正常情況回傳

HTTP Status Code: 200  
{
    "success": "Add user succeed."
}

有缺任一個欄位,或是多出任何欄位的時候

HTTP Status Code: 400  
{
    "error": "All necessary information must be provided."
}

編輯使用者

有放什麼欄位,就更新什麼欄位。

PUT /api/user

{
    "username": <string>,
    "password": <string>
}

正常情況回傳

HTTP Status Code: 200  
{
    "success": "Edit user succeed."
}

有多出任何未定義欄位的時候

HTTP Status Code: 400  
{
    "error": "All necessary information must be provided."
}

檢視目前登入 (session) 的使用者

GET /api/user/now

已登入的情況回傳

{
    "username": <string>,
    "user_id": <int>,
    "userDeviceIdList": <Array<userDevice>>
}

登入

登入以後在 session 資料中加入目前登入的使用者資料

POST /api/user/login

{
    "username": <string>,
    "password": <string>
}

正常登入時回傳

HTTP Status Code: 200  
{
    "success": "Login succeed."
}

不要特別回傳一種 『找到帳號,但是密碼錯誤』的結果,反而會讓有心人去踹密碼

使用者或帳號密碼錯誤時回傳

HTTP Status Code: 403  
{
    "error": "Username or password is wrong."
}

登出

登出以後清除記錄在 session 的使用者資料

POST /api/user/logout

正常登出時回傳

HTTP Status Code: 200  
{
    "success": "Logout succeed."
}

未登入時回傳

HTTP Status Code: 401  
{
    "error": "You didn't login."
}

推播裝置 API

新增裝置

POST /api/device

{
    "user_id": <int>,
    "player_id": <string>
}

正常情況回傳

HTTP Status Code: 200  
{
    "success": "Add device succeed."
}

有缺任一個欄位,或是多出任何欄位的時候

HTTP Status Code: 400  
{
    "error": "All necessary information must be provided."
}

提供的 user_id 不存在時

HTTP Status Code: 404  
{
    "error": "User not found."
}

推播 API

發送推播

targetId 是 OneSignal 的 playerId
targetGroup 可以是 "All" (寄送給全部裝置),或是 OneSignal 的 segment 名稱

發送以後要插記錄到 Notification_History ,一個targetId / targetGroup 一筆記錄

POST /api/notify  
{
    "content": <string>,
    "targetIdList": <Array<string>>,
    "targetGroupList": <Array<string>>
}

正常狀況的回傳

{
    "success": "Send notification succeed."
}

DB Schema

User 資料表

  • user_id: INTEGER
  • username: VARCHAR(255)
  • password: VARCHAR(255)
  • password_salt: VARCHAR(255)
  • created_at: TIMESTAMP 預設值:現在時間
  • updated_at: TIMESTAMP 預設值:現在時間

Device 資料表

  • device_id: INTEGER
  • player_id: VARCHAR(255)
  • user_id: INTEGER FOREIGN KEY (User.user_id)
  • created_at: TIMESTAMP 預設值:現在時間
  • updated_at: TIMESTAMP 預設值:現在時間

Notification_History 資料表

  • history_id: INTEGER
  • content: TEXT
  • target_id: VARCHAR(255)
  • target_group: VARCHAR(255)
  • created_at: TIMESTAMP 預設值:現在時間
  • updated_at: TIMESTAMP 預設值:現在時間

要求

主要目標

  • Web 框架使用 express
  • 資料庫使用 MySQL
  • 操縱資料庫可以使用 Sequelize.js (ORM)、knex.js (SQL Query builder) 或 RAW Query,使用 RAW Query 的話,傳入的資料一率 Escape 過,或是使用 Prepared Statement
  • 密碼要經過 Hash 過,使用 SHA256 / SHA384 / SHA512,salt 隨機產生以後和原始密碼接在一起以後送去 Hash,最後紀錄 Hash 出來的結果和 salt
  • session 使用 express-session,儲存 session 可以使用 MySQL 或 redis,偷懶不想多裝一個的話,就先用 MySQL 吧
  • body-parser 只在要用的 route 裡面使用,不要偷懶直接 app.use,一來浪費效能,二來怕 parse 到其他格式的內容,怕不小心抓到預期以外的資料

次要目標

  • 使用 ajv 來做資料驗證
  • 發送推播的 API,可以先做對單一 playerId 的推播,再做對 segment 的推播

參考資料: C-Far 網站原始碼

Ikaros

Read more posts by this author.