home: false
title: 服務編排配置
創建服務
創建聚合接口
配置輸入
- 配置輸入的定義包括3部分:請求頭、請求體和Query參數
- 基於JSON Schema規範
- 自帶校驗規則
- 支持自定義腳本實現複雜的邏輯校驗
JSON Schema規範,詳見:
http://json-schema.org/specification.html
http://json-schema.org/understanding-json-schema/
配置校驗結果
- 校驗不通過時,Fizz會把校驗失敗的原因(如:訂單ID不能爲空)放到上下文的validateMsg字段裏
- 可以自定義返回給調用方的報文格式,如 msgCode, message
- 支持自定義響應頭
- 支持自定義腳本處理校驗結果
配置步驟
配置步驟的基礎信息
配置步驟的接口入出參
步驟說明
- 一個聚合接口可包含多個步驟
- 一個步驟可包含多個請求(即調用多個接口)
- 步驟間是串聯順序執行
- 一個步驟內的多個請求並行執行
數據轉換
支持配置固定值,引用值和腳本
固定值
引用值
腳本
星號 *
星號通配符可以接收一個返回對象類型的引用值,返回對象裏的字段會合併到目標對象裏
樣例:userInfo = {"userName": "Fizz", "userID": 1234}
優先級與覆蓋順序
固定值 < 引用值 < 腳本 < 星號*
當一個字段配置了多種類型的值時按以上順序覆蓋,星號優先級最高
引用值規範
# 獲取入參請求頭aaa的值
input.request.headers.aaa
# 獲取入參請求體bbb字段的值
input.request.body.bbb
# 獲取入參URL Query參數fff字段的值
input.request.params.fff
# 獲取步驟1裏request1的請求頭ccc的值
step1.request1.request.headers.ccc
# 獲取步驟1裏request1的響應體ddd的值
step1.request1.response.body.ddd
# 獲取步驟1結果裏eee的值
step1.result.eee
- 支持單值引用,如:string,int等
- 支持對象類型的引用
input: 表示調用方的輸入數據,如H5頁面提交上來的參數
stepN.requestN: 表示步驟N裏調用接口N的相關參數
stepN.result: 表示步驟N的轉換結果
Fallback與預處理條件
Fallback:
當調用接口發生異常(如超時、網絡或系統異常)可配置fallback方案:
- Stop: 終止請求並立即返回
- Continue: 繼續後續的操作,且要設置默認的fallback json
預處理: 根據條件判斷是否要調用接口,腳本返回true時才調用接口
配置步驟結果處理
支持對步驟裏調用的每一個接口的返回結果做數據轉換,如果配置數據轉換規則原樣返回並存儲到上下文裏供後續使用
支持對步驟裏調用的一個或多個接口的返回結果做處理,並把處理完的結果存儲到上下文裏供後續使用,不配置則不處理
配置輸出
配置返回給調用方的結果
- 支持配置響應頭
- 支持配置響應體
- 支持自定腳本處理複雜的業務邏輯
腳本
目前支持以下腳本語言:
Javascript (推薦) - ECMAScript 5標準
JS腳本只支持單函數,且函數名不可變,在創建腳本時系統會自動生成初始模板,模板裏包含相關使用說明
Groovy
common.js 提供了操作context上下文的便捷操作函數
/**
* context 上下文便捷操作函數
*
*/
var common = {
/* *********** private function begin *********** */
// 獲取上下文中客戶端請求對象
getInputReq: function (ctx) {
if (!ctx || !ctx['input'] || !ctx['input']['request']) {
return {};
}
return ctx['input']['request']
},
// 獲取上下文步驟中請求接口的請求對象
getStepReq: function (ctx, stepName, requestName) {
if (!ctx || !stepName || !requestName) {
return {};
}
if (!ctx[stepName] || !ctx[stepName]['requests'] || !ctx[stepName]['requests'][requestName] ||
!ctx[stepName]['requests'][requestName]['request']) {
return {};
}
return ctx[stepName]['requests'][requestName]['request'];
},
// 獲取上下文步驟中請求接口的響應對象
getStepResp: function (ctx, stepName, requestName) {
if (!ctx || !stepName || !requestName) {
return {};
}
if (!ctx[stepName] || !ctx[stepName]['requests'] || !ctx[stepName]['requests'][requestName] ||
!ctx[stepName]['requests'][requestName]['response']) {
return {};
}
return ctx[stepName]['requests'][requestName]['response'];
},
/* *********** private function end *********** */
/* *********** input begin ************ */
/**
* 獲取客戶端請求頭
* @param {*} ctx 上下文 【必填】
* @param {*} headerName 請求頭字段名 【選填】,不傳時返回所有請求頭
*/
getInputReqHeader: function (ctx, headerName) {
var req = this.getInputReq(ctx);
var headers = req['headers'] || {};
return headerName ? headers[headerName] : headers;
},
/**
* 獲取客戶端URL請求參數(query string)
* @param {*} ctx 上下文 【必填】
* @param {*} paramName URL參數名 【選填】,不傳時返回所有請求參數
*/
getInputReqParam: function (ctx, paramName) {
var req = this.getInputReq(ctx);
var params = req['params'] || {};
return paramName ? params[paramName] : params;
},
/**
* 獲取客戶端請求體
* @param {*} ctx 上下文 【必填】
* @param {*} field 字段名 【選填】,不傳時返回整個請求體
*/
getInputReqBody: function (ctx, field) {
var req = this.getInputReq(ctx);
var body = req['body'] || {};
return field ? body[field] : body;
},
/**
* 獲取返回給客戶端的響應頭
* @param {*} ctx 上下文 【必填】
* @param {*} headerName 響應頭字段名 【選填】,不傳時返回所有響應頭
*/
getInputRespHeader: function (ctx, headerName) {
var req = this.getInputReq(ctx);
var headers = req['headers'] || {};
return headerName ? headers[headerName] : headers;
},
/**
* 獲取返回給客戶端的響應體
* @param {*} ctx 上下文 【必填】
* @param {*} field 字段名 【選填】,不傳時返回整個響應體
*/
getInputRespBody: function (ctx, field) {
var req = this.getInputReq(ctx);
var body = req['body'] || {};
return field ? body[field] : body;
},
/* *********** input begin ************ */
/* *********** step request begin ************ */
/**
* 獲取步驟中調用的接口的請求頭
* @param {*} ctx 上下文 【必填】
* @param {*} stepName 步驟名【必填】
* @param {*} requestName 請求的接口名 【必填】
* @param {*} headerName 請求頭字段名 【選填】,不傳時返回所有請求頭
*/
getStepReqHeader: function (ctx, stepName, requestName, headerName) {
var req = this.getStepReq(ctx, stepName, requestName);
var headers = req['headers'] || {};
return headerName ? headers[headerName] : headers;
},
/**
* 獲取步驟中調用的接口的URL參數
* @param {*} ctx 上下文 【必填】
* @param {*} stepName 步驟名【必填】
* @param {*} requestName 請求的接口名 【必填】
* @param {*} paramName URL參數名 【選填】,不傳時返回所有URL參數
*/
getStepReqParam: function (ctx, stepName, requestName, paramName) {
var req = this.getStepReq(ctx, stepName, requestName);
var params = req['params'] || {};
return paramName ? params[paramName] : params;
},
/**
* 獲取步驟中調用的接口的請求體
* @param {*} ctx 上下文 【必填】
* @param {*} stepName 步驟名【必填】
* @param {*} requestName 請求的接口名 【必填】
* @param {*} field 字段名 【選填】,不傳時返回整個請求體
*/
getStepReqBody: function (ctx, stepName, requestName, field) {
var req = this.getStepReq(ctx, stepName, requestName);
var body = req['body'] || {};
return field ? body[field] : body;
},
/**
* 獲取步驟中調用的接口的響應頭
* @param {*} ctx 上下文 【必填】
* @param {*} stepName 步驟名【必填】
* @param {*} requestName 請求的接口名 【必填】
* @param {*} headerName 響應頭字段名 【選填】,不傳時返回所有響應頭
*/
getStepRespHeader: function (ctx, stepName, requestName, headerName) {
var resp = this.getStepResp(ctx, stepName, requestName);
var headers = resp['headers'] || {};
return headerName ? headers[headerName] : headers;
},
/**
* 獲取步驟中調用的接口的響應頭
* @param {*} ctx 上下文 【必填】
* @param {*} stepName 步驟名【必填】
* @param {*} requestName 請求的接口名 【必填】
* @param {*} field 字段名 【選填】,不傳時返回整個響應頭
*/
getStepRespBody: function (ctx, stepName, requestName, field) {
var resp = this.getStepResp(ctx, stepName, requestName);
var body = resp['body'] || {};
return field ? body[field] : body;
},
/**
* 獲取步驟結果
* @param {*} ctx 上下文 【必填】
* @param {*} stepName 步驟名【必填】
* @param {*} field 字段名 【選填】,不傳時返回整個步驟結果對象
*/
getStepResult: function (ctx, stepName, field) {
if (!ctx || !stepName || !ctx[stepName]) {
return {};
}
var result = ctx[stepName]['result'] || {};
return field ? result[field] : result;
}
/* *********** step request end ************ */
};
context.js 數據結構
// 上下文,用於保存客戶輸入輸出和每個步驟的輸入與輸出結果
var context = {
// 是否DEBUG模式
debug:false,
// 各個操作的耗時
elapsedTimes: [{
[actionName]: 123, // 操作名稱:耗時
}],
// 客戶輸入和接口的返回結果
input: {
request:{
path: "",
method: "GET/POST",
headers: {},
body: {},
params: {}
},
response: { // 聚合接口的響應
headers: {},
body: {}
}
},
// 步驟
step1: {
requests: {
// 接口1
request1: {
// 請求相關參數
request:{
url: "",
method: "GET/POST",
headers: {},
body: {}
},
// 根據轉換規則轉換後的接口響應
response: {
headers: {},
body: {}
}
},
// 接口2
request2: {
request:{
url: "",
method: "GET/POST",
headers: {},
body: {}
},
response: {
headers: {},
body: {}
}
}
//...
},
// 步驟結果
result: {}
}
};
異常處理
當要在腳本里中止請求時可以通過以下方式來實現
返回一個對象且這個對象包含一個_stopAndResponse等於true的屬性,Fizz會終止後續的操作並把這個對象返回給調用方。
在線測試
- 支持在線實時測試
- 支持測試接口和正式接口隔離
- 支持返回上下文,可以查看整個執行過程中各個步驟及請求的輸入與輸出
- 支持保存歷史測試記錄
支持調試模式,在測試接口和正式接口均可使用,修改後重新發布可實時生效,在調試模式下會打印請求日誌及報文,主要用於排查線上問題
導入導出
導入導出主要用於在各個環境間同步接口配置,在開發環境配置好後導到測試環境中測試,測試完後導到生產環境進行發佈
發佈|下線和審覈
目前發佈|下線申請有以上兩個入口。
- 批量發佈:對發佈單裏的接口進行批量發佈
- 批量回滾:對發佈單裏的接口進行批量回滾
- 發佈:實時發佈到網關
- 回滾:支持回滾到歷史任何一個版本,可在發佈歷史裏指定一個版本進行回滾
- 下線:從網關刪除接口,在後臺可以通過發佈功能再次上線
發佈流程說明
申請發佈、審覈、發佈和下線功能的權限可根據需要靈活分配給不同角色,如:開發人員只能申請發佈,上級領導審覈,運維或測試人員執行發佈、回滾或下線。在開發、測試和預生產環境爲了方便開發人員調試也可把申請發佈、審覈、發佈和下線功能都分配給開發人員。