# Create service

# Create aggregate interface

# Configuration input

  • The definition of configuration input includes 3 parts: request header, request body and Query parameters
  • Supports JSON and XML type request bodies
  • Comes with verification rules
  • Support custom scripts to implement complex logic verification

Data verification follows the JSON Schema specification. For details, see:

http://json-schema.org/specification.html (opens new window)

http://json-schema.org/understanding-json-schema/ (opens new window)

# Configure verification results

  • When the verification fails, FizzGate will put the reason for the verification failure (for example: the order ID cannot be empty) into the validateMsg field of the context.
  • You can customize the message format returned to the caller, such as msgCode, message
  • Support custom response headers
  • Support custom scripts to process verification results

# Configuration steps (v2)

# Step instructions

  • An aggregate interface can contain multiple steps
  • One step can contain multiple requests (i.e. call multiple interfaces), supporting RESTful/Dubbo/gRPC interfaces
  • The steps are executed in series sequence
  • Multiple requests within one step are executed in parallel

# Basic information of configuration steps

Support RESTful/Dubbo/gRPC interface

The gRPC service needs to enable the reflection function, example:

server = ServerBuilder.forPort(port)
     .addService(new UserService())
     .addService(new ShoppingCartService())
     // gRPC reflection enabled
     .addService(ProtoReflectionService.newInstance())
     .build();

# Interface input and output parameters of the configuration step

Fields support multiple levels, separated by dots, such as user.name or user.age

The request body and response body of the RESTful interface support JSON and XML content types. The system will convert XML to JSON and configure it in JSON format during configuration. The XML and JSON conversion rules are as follows:

  • Each element (node) will be converted into a JSON object, and sub-elements will be converted into fields of the JSON object

  • The attribute name of the element is converted into a field of the JSON object, and the field name will be prefixed with a hyphen.

  • When the element has attributes, the content of the element is converted to the #text field of the JSON object

    <?xml version="1.0" encoding="utf-8"?>
    <library>
        <owner>John Doe</owner>
        <book id="007">James Bond</book>
        <book id="000">Book for the dummies</book>
    </library>
    

    Convert to JSON:

    {
      "library": {
        "owner": "John Doe",
        "book": [
          {
            "-id": "007",
            "#text": "James Bond"
          },
          {
            "-id": "000",
            "#text": "Book for the dummies"
          }
        ]
      }
    }
    
    <?xml version="1.0" encoding="utf-8"?>
    <library>
        <owner>John Doe</owner>
        <date>2021-03-31</date>
    </library>
    

    Convert to JSON:

    {
      "library": {
        "owner": "John Doe",
        "date": "2021-03-31"
      }
    }
    
    <?xml version="1.0" encoding="utf-8"?>
    <library>
        <book>James Bond</book>
    </library>
    

    Converted to JSON by default:

    {
      "library": { "book": "James Bond" }
    }
    

    It can be converted to JSON by specifying the array node path /library/book:

    {
      "library": { "book": ["James Bond"] }
    }
    

# Configuration steps (v3)

# Editor description

The v3 version adds a new API aggregation editor, which supports arrangement in the form of a flow chart, which is convenient and intuitive. Features and limitations are as follows:

  • Support request node and container node
  • Support conditional components and loop components
  • Supports concurrent and serial execution
  • Supports branching and aggregation
  • An aggregate interface can contain several nodes (request nodes or container nodes)
  • A container node can contain 0 or several request nodes
  • A container node can only contain at most one start node and at most one end node.
  • Nodes within the container cannot connect to nodes outside the container

# API Aggregation Editor

# Operation Guide

  • Drag the node on the left to the right area to add it
  • Drag the conditional component and loop component on the left to the request node or container node on the right to add components.
  • Double-click the node obtained on the right to edit the node properties
  • Click the component area below the node to edit component properties (as shown in the picture above, circle 2 areas)

# Sample

# Data conversion

Supports configuration of fixed values, reference values, functions and scripts

# Fixed value

# Reference value

# Function

For function-related documents, please refer to: Built-in function list>>

# Script

# Asterisk *

The asterisk wildcard can receive a reference value of the returned object type, and the fields in the returned object will be merged into the target object.

Example: If: step1.request2.response.body = {"userName": "FizzGate", "userID": 999} Then the output of the entire interface is {"userName": "FizzGate", "userID": 999, "a": 123}

# Tilde ~

The tilde wildcard is used to transparently transmit data. If the tilde wildcard is configured, the configuration of other fields will be ignored. The tilde wildcard can receive any data type, and the received value will be directly assigned to the corresponding body, request header or Query parameter.

Example: If: step1.request2.response.body = {"userName": "FizzGate", "userID": 999} Then the output of the entire interface is {"userName": "FizzGate", "userID": 999}, and other fields (a, dubbo_result, grpc_result) will be ignored.

# Priority and coverage order

Fixed value < reference value/function < script < asterisk* < tilde~

When a field is configured with multiple types of values, they are covered in the above order, and the wildcard has the highest priority.

# Reference value specification

Get the value of the input parameter request header aaa
input.request.headers.aaa

Get the value of the bbb field in the request body
input.request.body.bbb

Get the value of the fff field of the input URL Query parameter
input.request.params.fff

Get the value of the request header ccc of request1 in step 1
step1.request1.request.headers.ccc

Get the value of the response body ddd of request1 in step 1
step1.request1.response.body.ddd

Get the value of eee in the result of step 1
step1.result.eee

Get the value of the response code of request1 in step 1
step1.request1.response.httpStatus

Get the value of public resource account.name
g.account.name

Default value: input.request.body.bbb|123
The pipe character | is followed by the default value. When the reference value is empty, the default value is returned.

  • Support single value reference, such as: string, int, etc. -Supports references to object types

input: represents the input data of the caller, such as the parameters submitted on the H5 page

stepN.requestN: Represents the relevant parameters of calling interface N in step N

stepN.result: represents the conversion result of step N

g: represents public resources (management background: gateway management->public resources)

For example: there is a public resource account={"name":"abc","password":"123456"}, g.account.name means referencing the value of name in account: abc, g.account means referencing the value of account: {"name":"abc","password":"123456"}

# Jsonpath specification

Note: Reference values only support the following JsonPath operations

  • Use single quotes for strings, for example: ['name']
  • Filter operations are separated by spaces, for example: [?(@.type == 1)]
Support operations Description
@ Current node (used as a predicate of filter expression)
* Universal match, which can represent a name or number.
.. Deep scan. It can be understood as a recursive search.
.<name> represents a child node
['<name>' (, '<name>')] Represents one or more child nodes
[<number> (, <number>)] Represents one or more array subscripts (the negative sign is the reciprocal)
[?(<expression>)] Filter expression. The expression result must be a Boolean value.
Supports filtering operators (spaces must be added on both sides of the operator) Description
== left is equal to right (note that 1 is not equal to '1')
!= Not equal to
< less than
<= Less than or equal to
> Greater than
>= Greater than or equal to
=~ Match regular expression [?(@.name =~ /foo.*?/i)]
in The left side exists on the right side [?(@.size in ['S', 'M'])]
nin The left side does not exist on the right side
Support tail function Description
min() Calculate the minimum value of an array of numbers
max() Calculate the maximum value of a numeric array
avg() Calculate the average of an array of numbers
sum() Calculate the summary value of an array of numbers
length() Counts the number of elements in a numeric array

Example:

If the return body of request 1 in step 1 is as follows:

{
     "name": "ABCD",
     "data": [
         {
             "id": 1,
             "title": "title 1",
             "hits": 32344
         },
         {
             "id": 2,
             "title": "title 2",
             "hits": 566
         },
         {
             "id": 3,
             "title": "title 3",
             "hits": 7889
         },
         {
             "id": 4,
             "title": "title 4",
             "hits": 100
         },
         {
             "id": 5,
             "title": "title 5",
             "hits": 1688
         }
     ]
}

The following results can be obtained through the reference value expression in the above figure:

{
     "hits": [
         32344,
         566,
         7889,
         100,
         1688
     ],
     "name": "ABCD",
     "totalHits": 42587,
     "allTitleList": [
         "title 1",
         "title 2",
         "title 3",
         "title 4",
         "title 5"
     ],
     "id2Title": "title 2"
}

For more examples, please refer to the JsonPath official documentation: https://github.com/json-path/JsonPath

# Fallback and preprocessing conditions

Fallback:

When an exception occurs in the calling interface (such as timeout, network or system exception), a fallback scheme can be configured:

  • Stop: terminate the request and return immediately
  • Continue: Continue with subsequent operations and set the default fallback json

Preprocessing: Determine whether to call the interface based on conditions, and call the interface only when the script returns true

# Configuration step result processing

  • Supports data conversion of the return results of each interface called in the step. If the data conversion rules are not configured, the results will be returned as they are and stored in the context for subsequent use.

  • Supports processing the return results of one or more interfaces called in the step, and storing the processed results in the context for subsequent use. If not configured, it will not be processed.

# Configure output

Configure the results returned to the caller

-Support configuring response headers -Support configuring response body

  • Support custom scripts to handle complex business logic

# Script

# Introduction

FizzGate supports service orchestration through custom scripts:

  • Verify input content through script in configuration input;
  • In Configuration Output, the output content is defined through scripts, which can also be refined to the script processing of a certain output field;
  • In configuration step, define the return content of configuration input parameters and configuration response through script;
  • In Result Verification, you can fully customize the verification logic through scripts and verify the output content.

FizzGate supports two scripting languages, javascript and groovy, allowing developers to flexibly choose the language they are familiar with for service orchestration.

If you use javascript, you can obtain a series of tool functions through the common object to facilitate logical processing;

In groovy, all tool functions are mounted under context, and you can use them easily.

# Script writing format

# javascript

When writing JavaScript scripts, you need to write them in the following fixed format. function name dyFunc cannot be modified.

The return value can only be basic types, such as string/number/boolean, and the object/array type must be returned after serialization through JSON.stringify.

FizzGate executes javascript scripts by calling the js engine, and then captures the execution results. It can only obtain basic data types.

Before the object/array type is captured, the toString method on the prototype will be called, and the result is a string of [object type], which is not the expected data, so it must be serialized through JSON.stringify() jsonString and then return.

Do not use document and other APIs in js

function dyFunc(paramsJsonStr) {
     var ctx = JSON.parse(paramsJsonStr)['context'];
     // do something...
    
     // return string/number/boolean/jsonString
     return JSON.stringify({});
}

# groovy

When writing groovy scripts, you can return any data type supported by groovy.

import com.alibaba.fastjson.JSON
import com.alibaba.fastjson.JSONArray
import com.alibaba.fastjson.JSONObject

// do something...

// return any result
return result

# Configuration input - script verification

When editing the service orchestration interface, it is allowed to perform customized script verification on the input data in configuration input to verify whether the request header, request body, and query parameters pass the verification.

The returned verification result must be a serialized array, and:

  • If the verification passes, an empty array is returned;
  • If the verification fails, the error message of the failed verification will be pushed into the array and returned.

Reference example:

javascript

function dyFunc(paramsJsonStr) {
     var ctx = JSON.parse(paramsJsonStr)['context'];
     // Get the data input by the user of the aggregation interface
     // Get request headers
     var token = common.getInputReqHeader(ctx, 'token');
     // Get request parameters
     var account = common.getInputReqParam(ctx, 'account');
     var validate = [];
    
     //Verify request parameters
     if (!token) {
         // Push the error message of failed verification to validate
         validate.push('missing token');
     }
    
     if (!account) {
         validate.push('missing account');
     }
    
     // Return the array validate after serialization
     // An empty array indicates that the verification passed, and a non-empty array indicates that the verification failed.
     return JSON.stringify(validate);
}

groovy

// Get the data input by the user of the aggregation interface
// Get request headers
String token = context.getInputReqHeader('token')
// Get request parameters
String account = context.getInputReqAttr('params').get('account')
List<String> validate = new LinkedList<>()

//Verify request parameters
if (token == null || token.trim().isEmpty()) {
     //Add the error message of failed verification to validate
     validate.add('missing token')
}

if (account == null || account.trim().isEmpty()) {
     validate.add('missing account')
}

// An empty array indicates that the verification passed, and a non-empty array indicates that the verification failed.
return validate

# Configure output

# Output complete response

When editing the service orchestration interface, you are allowed to customize the output results in Configuration Output.

For the return result, it is recommended to return it in the data structure of {status code, request information, request result}. The example is as follows:

{
     "msgCode": 0, // status code
     "message": "success", // Request information
     "data": { //Request result
         "count": 1
     }
}

When the script is executed internally, an exception is detected and the request needs to be terminated. You can add _stopAndResponse: true to the response result for interruption and directly return the current result to the user.

{
     "msgCode": 1, // status code
     "message": "request error",
     "_stopAndResponse": true // Terminate the request and return the response result
}

Configuration output script example:

//The javascript script function name cannot be modified
function dyFunc(paramsJsonStr) {
   var context = JSON.parse(paramsJsonStr)['context'];
   var data = common.getStepRespBody(context, 'step2', 'request1', 'data');

   // do something


   // Customize the return result. If the returned Object contains the _stopAndResponse=true field, the request will be terminated and the script result will be responded to the client (mainly used in scenarios where abnormal situations require terminating the request)
   var result = { // There are no other special requirements for the data structure in result. The msgCode/message/data field is only an example.
     // _stopAndResponse: true,
     msgCode: '0',
     message: '',
     data: data
   };
   // When the return result is Array or Object, it must be converted into a json string first.
   return JSON.stringify(result);
}

# Single field output script processing

When editing the service orchestration interface, it is allowed to customize the value of a single field through script processing in configuration output.

In field configuration, after selecting Script, you can configure the value of a single field through script.

The result of the script execution here is only assigned to a single field.

//The javascript script function name cannot be modified
function dyFunc(paramsJsonStr) {
   var context = JSON.parse(paramsJsonStr)['context'];
   var token = common.getStepRespBody(context, 'step2', 'request1', 'token');

   // do something
   var memberId = parseToken(token);
   return memberId;
}

# Configuration steps

Same as Configuration Input - Script Verification and Configuration Output above.

# Result verification

Result verification refers to verifying the data finally returned to the user.

The returned verification result must be a serialized array, and:

  • If the verification passes, an empty array is returned;
  • If the verification fails, the error message of the failed verification will be pushed into the array and returned.

Reference example:

javascript

function dyFunc(paramsJsonStr) {
     var ctx = JSON.parse(paramsJsonStr)['context'];
     // Get the data input by the user of the aggregation interface
     // Get request headers
     var token = common.getInputReqHeader(ctx, 'token');
     // Get request parameters
     var account = common.getInputReqParam(ctx, 'account');
     var validate = [];
    
     //Verify request parameters
     if (!token) {
         // Push the error message of failed verification to validate
         validate.push('missing token');
     }
    
     if (!account) {
         validate.push('missing account');
     }
    
     // Return the array validate after serialization
     // An empty array indicates that the verification passed, and a non-empty array indicates that the verification failed.
     return JSON.stringify(validate);
}

groovy

// Get the data input by the user of the aggregation interface
// Get request headers
String token = context.getInputReqHeader('token')
// Get request parameters
String account = context.getInputReqAttr('params').get('account')
List<String> validate = new LinkedList<>()

//Verify request parameters
if (token == null || token.trim().isEmpty()) {
     //Add the error message of failed verification to validate
     validate.add('missing token')
}

if (account == null || account.trim().isEmpty()) {
     validate.add('missing account')
}

// An empty array indicates that the verification passed, and a non-empty array indicates that the verification failed.
return validate

# context in javascript script

The context in the javascript script is only in the scope of the scope function and is passed in as the first parameter of function dyFunc(paramsJsonStr){}.

function dyFunc(paramsJsonStr) {
     // The paramsJsonStr passed in is only a string, which needs to be serialized through JSON.parse to obtain `context`
     var ctx = JSON.parse(paramsJsonStr)['context'];
     // do something...
    
}

context data structure description:

interface context {
     debug: boolean; // Whether DEBUG mode
     elapsedTimes: elapsedTime[]; // Time consuming for each operation
     input: { //Customer input and interface return result
         request: { // request
             path: string; // Request path
             method: string; // Request method POST/GET/PUT/DELETE/...
             headers: {
                 [head: string]: any;
             }; // Request header
             body: {
                 [field: string]: any;
             }; // Request body
             params: {
                 [param: string]: any;
             }; // response body
         };
         response: { // response
             headers: {
                 [head: string]: any;
             }; // response header
             body: {
                 [field: string]: any;
             }; // Response body The response of the aggregate interface
         };
     };
     [stepName: string]: { // step
         [requestName: string]: { // interface
             request: { // // Request related parameters
                 url: string; // Request path
                 method: string; // Request method POST/GET/PUT/DELETE/...
                 headers: {
                     [head: string]: any;
                 }; // Request header
                 body: {
                     [body: string]: any;
                 }; // Request body
                 params: {
                     [param: string]: any;
                 }; // response body
             };
             response: { // Response The interface response converted according to the conversion rules
                 headers: {
                     [head: string]: any;
                 }; // response header
                 body: {
                     [field: string]: any;
                 }; // response body
             };
         }
     };
     result: string | number | boolean; // object/array needs to be serialized using JSON.stirngify
}

interface elapsedTime {
     [acticeName: string]: number; // Operation name: Time-consuming
}

In order to facilitate the use of context in scripts, we provide two script tool functions, javascript and groovy.

# Tool function——javascript

  • common.getInputReq(ctx):

    Get the request object in the context client

    • ctx: context
    function dyFunc(paramsJsonStr) {
        var ctx = JSON.parse(paramsJsonStr)['context'];
        var req = common.getInputReq(ctx);
    
        var path = req.path; // Request path
        var method = req.method; // Request method
        var headers = req.headers; // Request headers
        var body = req.body; // Request body
        var params = req.params; // Request parameters
        // do something...
        // return anything string
        return '';
    }
    
  • common.getStepReq(ctx, stepName, requestName):

    Get the request object of the request interface in the context step

    • ctx: context
    • stepName: step name in the configuration step
    • requestName: the request name corresponding to stepName in the configuration step
    function dyFunc(paramsJsonStr) {
        var ctx = JSON.parse(paramsJsonStr)['context'];
        var req = common.getStepReq(ctx, 'step1', 'request1');
       
        var url = req.url; //Request path
        var method = req.method; // Request method
        var headers = req.headers; // Request headers
        var body = req.body; // Request body
        var params = req.params; // Request parameters
        // do something...
        // return anything string
        return '';
    }
    
  • common.getStepResp(ctx, stepName, requestName)

    Get the response object of the request interface in the context step

    • ctx: context
    • stepName: step name in the configuration step
    • requestName: the request name corresponding to stepName in the configuration step
    function dyFunc(paramsJsonStr) {
        var ctx = JSON.parse(paramsJsonStr)['context'];
        var stepResp = common.getStepResp(ctx, 'step1', 'request1');
        // do something...
        // return anything string
        return '';
    }
    
  • common.getInputReqHeader(ctx, headerName)

    Get client request headers

    • ctx: context
    • headerName: request header field name [optional], if not passed, all request headers will be returned
    function dyFunc(paramsJsonStr) {
        var ctx = JSON.parse(paramsJsonStr)['context'];
        var contentType = common.getInputReqHeader(ctx, 'content-type');
        // do something...
        // return anything string
        return '';
    }
    
  • common.getInputReqParam(ctx, paramName)

    Get client URL request parameters (query string)

    • ctx: context
    • paramName URL parameter name [optional], if not passed, all request parameters will be returned
    function dyFunc(paramsJsonStr) {
        var ctx = JSON.parse(paramsJsonStr)['context'];
        var page = common.getInputReqParam(ctx, 'page');
        // do something...
        // return anything string
        return '';
    }
    
  • common.getInputReqBody(ctx, field)

    Get client request body

    • ctx: context
    • field field name [optional], if not passed, the entire request body will be returned
    function dyFunc(paramsJsonStr) {
        var ctx = JSON.parse(paramsJsonStr)['context'];
        var page = common.getInputReqBody(ctx, 'page');
        // do something...
        // return anything string
        return '';
    }
    
  • common.getInputRespHeader(ctx, headerName)

    Get the response headers returned to the client

    • ctx: context
    • headerName response header field name [optional], if not passed, all response headers will be returned
    function dyFunc(paramsJsonStr) {
        var ctx = JSON.parse(paramsJsonStr)['context'];
        var page = common.getInputRespHeader(ctx, 'content-type');
        // do something...
        // return anything string
        return '';
    }
    
  • common.getInputRespBody(ctx, field)

    Get the response body returned to the client

    • ctx: context
    • field field name [optional], if not passed, the entire response body will be returned
    function dyFunc(paramsJsonStr) {
        var ctx = JSON.parse(paramsJsonStr)['context'];
        var page = common.getInputReqBody(ctx, 'page');
        // do something...
        // return anything string
        return '';
    }
    
  • common.getStepReqHeader(ctx, stepName, requestName, headerName)

    Get the request header of the interface called in the step

    • ctx context [required]
    • stepName step name [required]
    • requestName requested interface name [required]
    • headerName request header field name [optional], if not passed, all request headers will be returned
    function dyFunc(paramsJsonStr) {
        var ctx = JSON.parse(paramsJsonStr)['context'];
        var contentType = common.getStepReqHeader(ctx, 'step1', 'request1', 'content-type');
        // do something...
        // return anything string
        return '';
    }
    
  • common.getStepReqParam(ctx, stepName, requestName, paramName)

    Get the URL parameters of the interface called in the step

    • ctx context [required]
    • stepName step name [required]
    • requestName requested interface name [required]
    • paramName URL parameter name [optional], if not passed, all URL parameters will be returned
    function dyFunc(paramsJsonStr) {
        var ctx = JSON.parse(paramsJsonStr)['context'];
        var page = common.getStepReqParam(ctx, 'step1', 'request1', 'page');
        // do something...
        // return anything string
        return '';
    }
    
  • common.getStepReqBody(ctx, stepName, requestName, field)

    Get the request body of the interface called in the step

    • ctx context [required]
    • stepName step name [required]
    • requestName requested interface name [required]
    • field field name [optional], if not passed, the entire request body will be returned
    function dyFunc(paramsJsonStr) {
        var ctx = JSON.parse(paramsJsonStr)['context'];
        var page = common.getStepReqBody(ctx, 'step1', 'request1', 'page');
        // do something...
        // return anything string
        return '';
    }
    
  • common.getStepRespHeader(ctx, stepName, requestName, headerName)

    Get the response header of the interface called in the step

    • ctx context [required]
    • stepName step name [required]
    • requestName requested interface name [required]
    • headerName response header field name [optional], if not passed, all response headers will be returned
    function dyFunc(paramsJsonStr) {
        var ctx = JSON.parse(paramsJsonStr)['context'];
        var contentType = common.getStepRespHeader(ctx, 'step1', 'request1', 'content-type');
        // do something...
        // return anything string
        return '';
    }
    
  • common.getStepRespBody(ctx, stepName, requestName, field)

    Get the response header of the interface called in the step

    • ctx context [required]
    • stepName step name [required]
    • requestName requested interface name [required]
    • field field name [optional], if not passed, the entire response header will be returned
    function dyFunc(paramsJsonStr) {
        var ctx = JSON.parse(paramsJsonStr)['context'];
        var page = common.getStepRespBody(ctx, 'step1', 'request1', 'page');
        // do something...
        // return anything string
        return '';
    }
    
  • common.getStepResult(ctx, stepName, field)

    Get step results

    • ctx context [required]
    • stepName step name [required]
    • field field name [optional], if not passed, the entire step result object will be returned
    function dyFunc(paramsJsonStr) {
        var ctx = JSON.parse(paramsJsonStr)['context'];
        var list = common.getStepResult(ctx, 'step1', 'list');
        // do something...
        // return anything string
        return '';
    }
    

# Tool function——groovy

  • context.getInputReq()

    Get the request object in the context client

    Map<String, Object> req = context.getInputReq()
    
  • context.getStepReq(stepName, requestName):

    Get the request object of the request interface in the context step

    • stepName: step name in the configuration step
    • requestName: the request name corresponding to stepName in the configuration step
    Map<String, Object> req = context.getStepReq('step1', 'request1')
    
  • context.getStepResp(stepName, requestName)

    Get the response object of the request interface in the context step

    • stepName: step name in the configuration step
    • requestName: the request name corresponding to stepName in the configuration step
  • context.getInputReqHeader(headerName)

    Get client request headers

    • headerName: request header field name [optional], if not passed, all request headers will be returned
  • context.getInputReqParam(paramName)

    Get client URL request parameters (query string)

    • paramName URL parameter name [optional], if not passed, all request parameters will be returned
  • context.getInputReqBody(field)

    Get client request body

    • field field name [optional], if not passed, the entire request body will be returned
  • context.getInputRespHeader(headerName)

    Get the response headers returned to the client

    • headerName response header field name [optional], if not passed, all response headers will be returned
  • context.getInputRespBody(field)

    Get the response body returned to the client

    • field field name [optional], if not passed, the entire response body will be returned
  • context.getStepReqHeader(ctx, stepName, requestName, headerName)

    Get the request header of the interface called in the step

    • stepName step name [required]
    • requestName requested interface name [required]
    • headerName request header field name [optional], if not passed, all request headers will be returned
  • context.getStepReqParam(stepName, requestName, paramName)

    Get the URL parameters of the interface called in the step

    • stepName step name [required]
    • requestName requested interface name [required]
    • paramName URL parameter name [optional], if not passed, all URL parameters will be returned
  • context.getStepReqBody(stepName, requestName, field)

    Get the request body of the interface called in the step

    • stepName step name [required]
    • requestName requested interface name [required]
    • field field name [optional], if not passed, the entire request body will be returned
  • context.getStepRespHeader(stepName, requestName, headerName)

    Get the response header of the interface called in the step

    • stepName step name [required]
    • requestName requested interface name [required]
    • headerName response header field name [optional], if not passed, all response headers will be returned
  • context.getStepRespBody(stepName, requestName, field)

    Get the response header of the interface called in the step

    • stepName step name [required]
    • requestName requested interface name [required]
    • field field name [optional], if not passed, the entire response header will be returned
  • context.getStepResult(stepName, field)

    Get step results

    • stepName step name [required]
    • field field name [optional], if not passed, the entire step result object will be returned

# Throw an exception

When you want to abort the request in the script, you can do it in the following way

Returning an object that contains a property with _stopAndResponse equal to true, FizzGate will terminate subsequent operations and return the object to the caller.

# Redirect

Redirection can be achieved through scripts. The script returns an object and this object contains both _stopAndResponse=true and _redirectUrl attributes. The value of _redirectUrl is the redirected target URL. FizzGate will terminate subsequent operations and redirect. A sample JavaScript script is as follows:

# Configure routing

At this point, the interface configuration of the service orchestration is completed. At this time, the interface cannot be accessed through the gateway. You need to configure the route in the gateway management-routing management.

  • The testing function of versions below v2.0.0 needs to configure routing before it can be tested, and the front-end and back-end service names and paths of routing need to be consistent;
  • The testing function of v2.0.0 or above does not require routing configuration by default and can be tested directly. You can enable test routing configuration by modifying the aggregate_test_auth configuration item in application.yml. Formal interfaces still need to be configured with routing before they can be accessed.

# Online test

-Support online real-time testing

  • Supports isolation of test interfaces and formal interfaces
  • Supports return context, allowing you to view the input and output of each step and request during the entire execution process -Supports saving historical test records

Supports debugging mode, which can be used in both test interfaces and official interfaces. Modifications can be republished to take effect in real time. In debugging mode, request logs and messages will be printed, which is mainly used to troubleshoot online problems.

# Script execution exception

When the script executes abnormally, exception information will be recorded in the context.

  • exceptionMessage exception message
  • exceptionStacks exception stack information
  • exceptionData script data that caused the exception
//Context data structure design
//Context, used to save customer input and output and the input and output results of each step
var context = {
//Whether DEBUG mode
debug:false,
	
// exception info
exceptionMessage: "",
exceptionStacks: "",
   exceptionData: "", // such as script source code that cause exception

   // ... other fields
}

Add returnContext=true to the request to return the context. Example of exception information:

# Import and Export

Import and export are mainly used to synchronize interface configurations between various environments. After the development environment is configured, it is exported to the test environment for testing. After testing, it is exported to the production environment for release.

# Publish|Offline and review

Currently there are two entrances for release|offline application.

  • Batch release: Batch release of the interfaces in the release order
  • Batch rollback: batch rollback of the interfaces in the release order
  • Publish: publish to the gateway in real time
  • Rollback: Supports rollback to any version in the history. You can specify a version in the release history for rollback.
  • Offline: Delete the interface from the gateway, and it can be brought online again through the publishing function in the background

# Release process description

The permissions to apply for release, review, release and offline functions can be flexibly assigned to different roles as needed. For example: developers can only apply for release, superior leaders can review, and operation and maintenance or testers can perform release, rollback or offline. In the development, testing and pre-production environments, in order to facilitate developer debugging, the application release, review, release and offline functions can also be assigned to developers.

# Configure request headers

Service orchestration will bring the following request headers by default when calling the backend interface: host,X-Real-IP,X-Forwarded-Proto,X-Forwarded-For

It can be modified in the application.yml configuration file of fizz-gateway-node:

gateway:
   aggr:
     # set headers when calling the backend API
     proxy_set_headers: host,X-Real-IP,X-Forwarded-Proto,X-Forwarded-For