# 用 Markdown 寫 API 規格教學 > 範例以「案件申貸狀態同步」與「案件推廣來源」兩個端點示範。 [TOC] --- ## 1. 文件說明(Overview) - **目的**:用 *Markdown* 撰寫一份清楚、可維護的 **API 規格**,包含端點定義、參數、請求/回應格式、錯誤碼、範例與 JSON Schema。 - **風格**:採「純 Markdown」為主,並補充「API Blueprint 速記法」區塊,方便團隊快速擬稿。 - **版本**:v1.0.0 - **主機(HOST)**:`https://[domain]/service/api/{Action}` - **認證**:`Authorization: Bearer {ACCESS_TOKEN}` - **內容格式**:`application/json; charset=utf-8` --- ## 2. 全域慣例(Conventions) - **時間格式**:除非特別註明,皆為 `yyyyMMdd` 或 `yyyy-MM-ddTHH:mm:ssZ`(UTC)。 - **字串編碼**:UTF-8。 - **安全性**:所有寫入類(POST/PUT/PATCH/DELETE)應驗證 Bearer Token。 - **冪等性(Idempotency)**:建議對關鍵寫入操作設計冪等鍵(如 `UPD_KEY`)。 - **錯誤模型**:統一以 `Result.ReturnCode != 0` 作為非成功訊號(見 §6)。 --- ## 3. 快速藍本:API Blueprint 速記法(*可選*) > 若團隊熟悉 API Blueprint,可用下列速記區塊在 HackMD 擬稿,等同於「規格提綱」。 ```apib FORMAT: 1A HOST: https://[domain]/service/api/{Action} # 雲端API ## 案件申貸狀態同步 [/SyncLoanCase] ### 取得案件申貸狀態 [GET] + Response 200 (application/json) [ { /* ... */ } ] ### 異動案件申貸狀態、相關欄位 [POST] + Headers Authorization: Bearer {ACCESS_TOKEN} + Request (application/json) { /* 請見正式規格 §4.2 請求體 */ } + Response 200 (application/json) { /* 請見正式規格 §4.3 回應體 */ } ``` > 下方為「正式 Markdown 版規格」,提供完整欄位說明、枚舉、JSON Schema 與範例。 --- ## 4. 端點:案件申貸狀態同步 `/SyncLoanCase` ### 4.1 取得案件申貸狀態(GET) - **Method**:`GET /SyncLoanCase` - **說明**:依查詢條件取得案件申貸狀態列表(若未提供條件,依系統預設限制返回最近更新)。 - **查詢參數(Query)**: | 參數 | 型別 | 必填 | 範例 | 說明 | |---|---|---|---|---| | `caseId` | string | 否 | `TEST123` | 指定單一案件編號 | | `updatedSince` | string(yyyyMMdd) | 否 | `20250101` | 只取此日期(含)之後異動 | | `page` | int | 否 | `1` | 分頁頁碼(>=1) | | `pageSize` | int | 否 | `50` | 單頁筆數(<=100) | - **成功回應 200(application/json)**: ```json [ { "CASE_ID": "TEST123", "CASE_STATUS": "1", "CASE_TYPE": "1", "UPDATED_AT": "2025-10-01T08:30:00Z" } ] ``` - **錯誤回應**:見 §6 錯誤模型。 --- ### 4.2 異動案件申貸狀態、相關欄位(POST) - **Method**:`POST /SyncLoanCase` - **說明**:更新案件申貸狀態與周邊資訊,支援冪等鍵 `UPD_KEY` 以避免重複寫入。 - **必要標頭(Headers)**: - `Authorization: Bearer {ACCESS_TOKEN}` - `Content-Type: application/json` - **請求體(Request Body)**:主要欄位如下;完整驗證規則見 §7 JSON Schema。 | 欄位 | 型別/格式 | 必填 | 範例 | 說明 | |---|---|---|---|---| | `MOTO_CASE_MAJ` | string | 是 | `"string"` | 案件唯一值 | | `CASE_TYPE` | enum string | 否 | `"1"` | `0=None, 1=Mobile, 2=Scooter, 3=Hybrid` | | `CASE_STATUS` | string | 否 | `"1"` | 申貸狀態代碼(內規定義) | | `PRD_NUM` | string | 否 | `"4000"` | 商品代碼 | | `PRD_AMT` | string | 否 | `"4000"` | 商品金額 | | `LOAN_AMT` | string | 否 | `"4000"` | 申貸金額 | | `HAND_FEE` | string | 否 | `"4000"` | 手續費 | | `DSB_AMT` | string | 否 | `"4000"` | 撥款金額 | | `CR_DOC_FILE_U_ID` | uuid string | 否 | `"ee1d662d-54ca-441e-919a-abe93b15d51d"` | 徵審文件檔 UUID | | `UPD_KEY` | string | 是 | `"{UPD_KEY}"` | 冪等鍵(同請求多次只生效一次) | | `SIGN_CONTRACT` | `"0"|"1"` | 否 | `"1"` | 是否簽約 | | `PAYMENT_UNUSUAL` | `"0"|"1"` | 否 | `"1"` | 付款是否異常 | | `CONTRACT_BEFORE_FILE_UUID` | uuid | 否 | `"ee1d...d51d"` | 簽約前檔案 | | `CONTRACT_SIGN_FILE_UUID` | uuid | 否 | `"ee1d...d51d"` | 簽約後檔案 | | `IS_ABT` | `"0"|"1"` | 否 | `"1"` | 是否棄件/撤件(依定義) | | `IS_END` | `"0"|"1"` | 否 | `"1"` | 是否已結案 | | `CONTACT_METHOD` | enum | 否 | `"1"` | 連絡方式代碼 | | `APP_FIRST_DT` | string(yyyyMMdd) | 否 | `"19990101"` | 初次申請日 | | `CREDIT_SCORE` | string | 否 | `"80"` | 信評分數 | | `CUST_ID` | string | 否 | `"X123123123"` | 身分證/統編 | | `MOBILE_1` | string | 否 | `"0912123123"` | 手機 | | `MOVABLES_AMT` | string | 否 | `"20000"` | 動產金額 | | `REAL_DSB_AMT` | string | 否 | `"1500"` | 實際撥款金額 | | `CC` | string | 否 | `"100"` | 其他代碼 | | `BIRTHDAY` | string(yyyyMMdd) | 否 | `"19880707"` | 生日 | | `MOBILE_IMEI_01` | string | 否 | `"357221098977524"` | IMEI | | `MOBILE_IMEI_02` | string | 否 | `"353990106364578"` | 备用 IMEI | | `MOBILE_BRAND` | string | 否 | `"Apple"` | 手機品牌 | | `MOBILE_MODEL` | string | 否 | `"6s"` | 手機型號 | | `ID_CARD_DATE` | string | 否 | `"20200101"` | 證件發證日(如適用) | | `CASE_ID` | string | 否 | `"TEST123"` | 案件代碼(系統/外部來源) | - **請求體範例**: ```json { "MOTO_CASE_MAJ": "string", "CASE_TYPE": "1", "CASE_STATUS": "1", "PRD_NUM": "4000", "PRD_AMT": "4000", "LOAN_AMT": "4000", "HAND_FEE": "4000", "DSB_AMT": "4000", "CR_DOC_FILE_U_ID": "ee1d662d-54ca-441e-919a-abe93b15d51d", "UPD_KEY": "{UPD_KEY}", "SIGN_CONTRACT": "1", "PAYMENT_UNUSUAL": "1", "CONTRACT_BEFORE_FILE_UUID": "ee1d662d-54ca-441e-919a-abe93b15d51d", "CONTRACT_SIGN_FILE_UUID": "ee1d662d-54ca-441e-919a-abe93b15d51d", "IS_ABT": "1", "IS_END": "1", "CONTACT_METHOD": "1", "APP_FIRST_DT": "19990101", "CREDIT_SCORE": "80", "CUST_ID": "X123123123", "MOBILE_1": "0912123123", "MOVABLES_AMT": "20000", "REAL_DSB_AMT": "1500", "CC": "100", "BIRTHDAY": "19880707", "MOBILE_IMEI_01": "357221098977524", "MOBILE_IMEI_02": "353990106364578", "MOBILE_BRAND": "Apple", "MOBILE_MODEL": "6s", "ID_CARD_DATE": "20200101", "CASE_ID": "TEST123" } ``` - **成功回應 200(application/json)**: ```json { "Data": { "IS_SUCCESS": "Y", "ERR_MSG": "" }, "Result": { "ReturnCode": 0, "ReturnMsg": "更新成功", "Alert": "更新成功", "Count": 1 } } ``` - **常見狀態碼**: - `200 OK`:更新成功 - `400 Bad Request`:參數格式錯誤、缺少必填欄位 - `401 Unauthorized`:Token 失效或未帶入 - `409 Conflict`:冪等鍵重複提交(已處理) - `422 Unprocessable Entity`:商業規則未通過 - `500 Internal Server Error`:伺服器錯誤 --- ## 5. 端點:案件推廣來源 `/NewsSrc` ### 5.1 取得案件推廣來源(GET) - **Method**:`GET /NewsSrc` - **說明**:取得推廣來源清單(僅返回 `IsEnable=1` 且依 `Sort` 排序)。 - **成功回應 200(application/json)**: ```json [ { "NewsValue": 1, "NewsText": "Google搜尋" }, { "NewsValue": 16, "NewsText": "貸鼠先生" }, { "NewsValue": 2, "NewsText": "網路廣告" }, { "NewsValue": 3, "NewsText": "簡訊推廣" }, { "NewsValue": 4, "NewsText": "新聞網站" }, { "NewsValue": 48, "NewsText": "電話推廣" }, { "NewsValue": 5, "NewsText": "報章雜誌" }, { "NewsValue": 6, "NewsText": "電視媒體" }, { "NewsValue": 7, "NewsText": "親友介紹" } ] ``` --- ## 6. 統一錯誤模型與處理建議 - **回應結構**(建議): ```json { "Result": { "ReturnCode": 1234, "ReturnMsg": "錯誤訊息", "TraceId": "dd0c836e-...", "Alert": "可顯示給使用者的友善提示" }, "Data": null } ``` - **處理原則**: - `ReturnCode = 0` 視為成功,其餘為失敗。 - 需記錄 `TraceId` 於後端日誌,方便追查。 - 對外錯誤訊息應避免洩露內部系統訊息。 --- ## 7. JSON Schema(請求體驗證:/SyncLoanCase POST) > 可用於前後端驗證與合約測試。 ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "SyncLoanCaseRequest", "type": "object", "additionalProperties": false, "properties": { "MOTO_CASE_MAJ": { "type": "string", "minLength": 1 }, "CASE_TYPE": { "type": "string", "enum": ["0", "1", "2", "3"] }, "CASE_STATUS": { "type": "string" }, "PRD_NUM": { "type": "string" }, "PRD_AMT": { "type": "string", "pattern": "^[0-9]+$" }, "LOAN_AMT": { "type": "string", "pattern": "^[0-9]+$" }, "HAND_FEE": { "type": "string", "pattern": "^[0-9]+$" }, "DSB_AMT": { "type": "string", "pattern": "^[0-9]+$" }, "CR_DOC_FILE_U_ID": { "type": "string", "format": "uuid" }, "UPD_KEY": { "type": "string", "minLength": 1 }, "SIGN_CONTRACT": { "type": "string", "enum": ["0", "1"] }, "PAYMENT_UNUSUAL": { "type": "string", "enum": ["0", "1"] }, "CONTRACT_BEFORE_FILE_UUID": { "type": "string", "format": "uuid" }, "CONTRACT_SIGN_FILE_UUID": { "type": "string", "format": "uuid" }, "IS_ABT": { "type": "string", "enum": ["0", "1"] }, "IS_END": { "type": "string", "enum": ["0", "1"] }, "CONTACT_METHOD": { "type": "string" }, "APP_FIRST_DT": { "type": "string", "pattern": "^\\d{8}$" }, "CREDIT_SCORE": { "type": "string", "pattern": "^[0-9]+$" }, "CUST_ID": { "type": "string" }, "MOBILE_1": { "type": "string" }, "MOVABLES_AMT": { "type": "string", "pattern": "^[0-9]+$" }, "REAL_DSB_AMT": { "type": "string", "pattern": "^[0-9]+$" }, "CC": { "type": "string" }, "BIRTHDAY": { "type": "string", "pattern": "^\\d{8}$" }, "MOBILE_IMEI_01": { "type": "string", "pattern": "^\\d{14,17}$" }, "MOBILE_IMEI_02": { "type": "string", "pattern": "^\\d{14,17}$" }, "MOBILE_BRAND": { "type": "string" }, "MOBILE_MODEL": { "type": "string" }, "ID_CARD_DATE": { "type": "string" }, "CASE_ID": { "type": "string" } }, "required": ["MOTO_CASE_MAJ", "UPD_KEY"] } ``` --- ## 8. 範例請求(cURL / C#) ### 8.1 cURL:POST /SyncLoanCase ```bash curl -X POST "https://[domain]/service/api/SyncLoanCase" \ -H "Authorization: Bearer {ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "MOTO_CASE_MAJ": "string", "UPD_KEY": "abc123", "CASE_STATUS": "1" }' ``` ### 8.2 C#:POST /SyncLoanCase(RestSharp 範例) ```csharp var client = new RestClient("https://[domain]/service/api/SyncLoanCase"); var req = new RestRequest(Method.Post); req.AddHeader("Authorization", "Bearer {ACCESS_TOKEN}"); req.AddHeader("Content-Type", "application/json"); req.AddStringBody(@"{ ""MOTO_CASE_MAJ"": ""string"", ""UPD_KEY"": ""abc123"", ""CASE_STATUS"": ""1"" }", DataFormat.Json); var res = await client.ExecuteAsync(req); Console.WriteLine(res.Content); ``` --- ## 9. Database 參考 SQL(對應 `/NewsSrc`) ```sql /****** SSMS 中 SelectTopNRows 命令的指令碼 ******/ SELECT [NewsValue], [NewsText] FROM [dbo].[NEWS_OPTION] WHERE IsEnable = 1 ORDER BY [Sort]; ``` --- ## 10. 撰寫檢查清單(Checklist) - [ ] 主機/環境位址是否明確(Dev/SIT/UAT/Prod) - [ ] 認證與權限(Bearer、Scopes)是否定義 - [ ] 必填欄位與枚舉值是否完整列出 - [ ] JSON Schema 是否覆蓋格式/型別/模式 - [ ] 回應模型(成功/錯誤)是否一致 - [ ] 範例(cURL/C#)是否可直接執行 - [ ] 變更紀錄(Changelog)是否更新 --- ## 11. 變更紀錄(Changelog) - **v1.0.0 (2025-10-06)**:初版釋出(新增 `/SyncLoanCase`、`/NewsSrc` 規格、JSON Schema、範例程式、SQL 參考)。