LoginSignup
9
2

More than 5 years have passed since last update.

[IBM API Connect] クエリパラメータを使って動的にAPIレスポンスの項目を制御する方法

Last updated at Posted at 2017-07-26

やりたいこと

複数の要素を返すバックエンドAPIの応答から、クライアントの指定した要素のみを抽出して返すAPIゲートウェイを構成する方法を考えてみます。例えば、GET /accounts/1001?mask=name,ageのように、変数(ここでは"mask")に項目名を指定することで、クライアント側で必要な項目だけを返すAPIを作ってみます。

GET_/accounts/1001
{
  "id" : "1001",
  "name" : "alice",
  "phone" : "000-000-0000",
  "gender" : "female", 
  "age" : 20
}

つまり、:arrow_up:これを:arrow_down:こうしたい。

GET_/accounts/1001?mask=name,age
{
   "name" : "alice",
   "age" : 20
}

前提、環境等

  • 2017/07/26 時点の IBM API Connect on Bluemix Public で動作を確認しています

実装

実装方針

IBM API Connectには様々なメッセージ変換部品が用意されていますが、今回はGatewayScriptポリシーを使ってみます。GatewayScriptポリシーの詳細はマニュアルを確認してください。

処理の流れ

処理の流れはこんな感じになります。
1. リクエスト・パラメートしてmaskを受け付ける
2. Invoke ポリシーでバックエンドAPIからアカウント情報のJSONを取得
3. GatewayScript ポリシーでmaskの内容に応じてアカウント情報をマスキング
3.1 Invokeの結果を変数に読み込む
3.2 maskパラメータをカンマで分割して変数に読み込む
3.3 Invokeの結果から、maskで指定された項目のみをコピーしたオブジェクトを組み立て
3.4 組み立てたオブジェクトを応答に書き出し

アセンブリー・フロー実装

フローの全体像はこんな感じになります。
image

invoke部分は適当なバックエンドを呼ぶように構成してください。また今回のサンプルではResponse Object Variableが指定されていない前提でmask-outputが書かれていますので、空であることを確認します。
image

GatewayScript実装

今回の主役であるmask-outputのコードはこんな感じです。

mask-output
apim.readInputAsJSON(function (error,inObj) {  
  // 前ステップ(invoke)の出力をinObjに読み込む
  if (error) {
    console.log("Failed to read data in JSON format");
  } else {
    var maskStr = apim.getvariable('request.parameters.mask');
    if (maskStr) {  
      // maskパラメータが存在する場合のみ、マスキングを実行
      var maskAry = maskStr.split(',');
      var outObj = {};

      for(let mask of maskAry){  
        // maskに指定された項目をoutObjにコピー
        if(inObj.hasOwnProperty(mask)){
          outObj[mask] = inObj[mask];
        }
      }

      // outObjの書き出し処理
      session.output.write(outObj);
      apim.output('application/json');
    }
  }
});

実行結果

API Managerのテストツールからテストしてみます。

maskパラメータを指定しない場合

image

mask=name,ageと指定した場合

image
無事に指定した項目で応答がマスクされました。

コード

今回作成したAPI定義はこちらです。target-url: "set-your-url-here"を適当な値に置き換えてご利用ください。

accounts-masked_1.0.0.yaml
---
swagger: "2.0"
info:
  x-ibm-name: "accounts-masked"
  title: "accounts-masked"
  version: "1.0.0"
schemes:
- "https"
host: "$(catalog.host)"
basePath: "/accounts-masked"
consumes:
- "application/json"
produces:
- "application/json"
securityDefinitions:
  clientIdHeader:
    type: "apiKey"
    in: "header"
    name: "X-IBM-Client-Id"
security:
- clientIdHeader: []
x-ibm-configuration:
  testable: true
  enforced: true
  cors:
    enabled: true
  assembly:
    execute:
    - invoke:
        target-url: "set-your-url-here"
    - gatewayscript:
        title: "mask-output"
        version: "1.0.0"
        source: "apim.readInputAsJSON(function (error,inObj) {  // 前ステップ(invoke)の出\
          力をinObjに読み込む\r\n  if (error) {\r\n    console.log(\"Failed to read data\
          \ in JSON format\");\r\n  } else {\r\n    var maskStr = apim.getvariable('request.parameters.mask');\r\
          \n    if (maskStr) {  // maskパラメータが存在する場合のみ、マスキングを実行\r\n      var maskAry\
          \ = maskStr.split(',');\r\n      var outObj = {};\r\n\r\n      for(let mask\
          \ of maskAry){  // maskに指定された項目をoutObjにコピー\r\n        if(inObj.hasOwnProperty(mask)){\r\
          \n          outObj[mask] = inObj[mask];\r\n        }\r\n      }\r\n\r\n\
          \      // outObjの書き出し処理\r\n      session.output.write(outObj);\r\n     \
          \ apim.output('application/json');\r\n    }\r\n  }\r\n});"
  phase: "realized"
paths:
  /accounts/{id}:
    get:
      responses:
        200:
          description: "200 OK"
      parameters:
      - name: "mask"
        type: "string"
        required: false
        in: "query"
        description: "Keys to be passed to client, in comma  separated value format."
    parameters:
    - name: "id"
      type: "string"
      required: true
      in: "path"
      description: "user id"
definitions:
  userInfo:
    description: ""
    type: "object"
    properties:
      id:
        type: "string"
      name:
        type: "string"
      phone:
        type: "string"
      gender:
        type: "string"
      age:
        type: "number"
    example: "{\r\n\"id\": \"1001\",\r\n\"name\": \"alice\",\r\n\"phone\": \"000-000-0000\"\
      ,\r\n\"gender\": \"female\",\r\n\"age\": 20\r\n}"
    additionalProperties: true
tags: []

参考情報

IBM Knowledge Center - GatewayScript

9
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
2