3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

KongAdvent Calendar 2024

Day 10

Kong GatewayのOAS Validation Pluginの使い方

Last updated at Posted at 2024-12-09

本記事は「Kong Advent Calendar 2024」の10日目のエントリとして、OAS Validation Pluginについて解説する。

APIを開発している時、APIサーバをデプロイしたものの、クライアント側の更新が追いつかず、結果としてサーバ側が期待するリクエストとは異なるリクエストをクライアントが飛ばしてしまうことがある。
これをKongで検知してサーバ側ではなくKongからエラーを返してトラシュを楽にしてくれるのがOAS Validation Pluginである。
どんな感じで使えるのが実際に触って確かめてみる。

検証

ここではチュートリアルを参考にSwagger.ioのSwagger Petstoreを使って検証する。

設定

Petstoreに繋ぐためのKong GatewayのServiceを作成する。

curl -X POST http://localhost:8001/services/ \
    --data name='Petstore-Service' \
    --data url='https://petstore.swagger.io/v2'

OAS Validation Pluginにはパスのチェックも含まれているため、ServiceとRouteのURLの切り方は少し意識する必要がある。
具体的にはAPIのエンドポイントが
<Serviceのホスト>/<Routeのパス>
となっている時、API Specには<Routeのパス>だけ含まれている必要がある。
例えば
https://petstore.swagger.io/v2/pet/findByStatus
というアクセス先に対し、API Specで/pet/findByStatusが定義されている場合、Serviceはhttps://petstore.swagger.io/v2となる。

次にRouteを作成する。

curl -X POST http://localhost:8001/services/Petstore-Service/routes \
    --data name='Petstore-Route' \
    --data paths='~/.*' \
    --data "strip_path=false"

少し面倒なのが、PluginによるパスチェックはRouteのパスも含まれる。
なので、ここでpaths=~/petstore/.*などとすると、パスチェックの際に/petstore/から始まるパスがAPI Specにあるかどうかをチェックしてしまうので、ここでは~/*としてAPI Specのパスから始まるように調整する。
(多分/petstore/などの指定もやり方次第で出来ると思うが、今回は確認していない)
また、strip_pathを無効化しないとパスが消えた状態で渡ってしまうのでエンドポイントから404が返ってくる。
単にチェックしたいだけの目的で使うならそれでもいいが、実際にアクセスしたい場合は今回の設定ではfalseにする必要がある。

次にPluginを設定する。
Pluginでは以下のパラメータを指定する。

  • config.api_spec:リクエストがAPI Specに沿っているかを確認する際に使うAPI Spec(文字列)
  • config.verbose_response:エラー時にメッセージを詳細化する
  • config.api_spec_encoded : URIエンコードした文字列を渡す場合はtrueにする

なお、今回はYAMLファイルでAPI Specを渡すが、API SpecをJSONで書いている人もいるかもしれない。
その場合はapi_spec_encodedは不要になる。

次にValidation対象のAPI Specを用意する。
ここではSwaggerのPetstoreが提供しているAPI Specを利用する。
以下でAPI Specをダウンロードする。

wget https://petstore3.swagger.io/api/v3/openapi.json -O /tmp/swagger_v3.json

今回はYAML形式のSpecを検証するため、JSON形式をYAMLに変換する。

yq -P < /tmp/swagger_v3.json > ./swagger_v3.yaml

PluginをServiceに対して設定する。

curl -X POST http://localhost:8001/services/Petstore-Service/plugins \
     --data name='oas-validation' \
     --data-urlencode config.api_spec@swagger_v3.yaml \
     --data config.verbose_response=true \
     --data config.api_spec_encoded=true

--data-urlencodeを使うことでYAMLをURIエンコードした状態で送っている。

動作確認

今回使うPetstoreはペットの情報をAPIで取得できるサンプルのサービスである。
色々なエンドポイントが用意されているが、ここでは/pet/findByStatusを触ってみる。
このエンドポイントはstatusのクエリが必須となっている。
20241115165353.png

API Specでは以下のように定義されている。

  /pet/findByStatus:
    get:
      tags:
        - pet
      summary: Finds Pets by status
      description: Multiple status values can be provided with comma separated strings
      operationId: findPetsByStatus
      produces:
        - application/json
        - application/xml
      parameters:
        - name: status
          in: query
          description: Status values that need to be considered for filter
          required: true
          type: array

ここにクエリなしでリクエストしてみる。

$ curl -X GET "http://localhost:8000/pet/findByStatus" -H "accept: application/json"

すると即座にレスポンスが返ってきた。

{"message":"query 'status' validation failed with error: 'required parameter value not found in request'"}

エラーメッセージには「必須パラメータがリクエストにない」と記載されており、OAS Validation PluginがAPI Specのrequired: trueからパラメータの不足を検知して、エンドポイントに飛ばすことなくエラーを検知してくれた。
なお、エラーコードは400となった。
OAS Validation Pluginがない場合はこんな感じ。

$ curl -X GET "https://petstore.swagger.io/v2/pet/findByStatus" -H "accept: application/xml"
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><pets></pets>

エラーコードは200であり、メッセージもエラーではないので原因が特定できない。
このように、OAS Validation Pluginがあればデバッグが少し楽になる。
ちなみにクエリをつけてやると、正常にデータが取得できる。

$ curl -X GET "http://localhost:8000/pet/findByStatus?status=available" -H "accept: application/json" -s | jq . | head -n 5
[
  {
    "id": 9223372016900015390,
    "category": {
      "id": 0,

もう少し試してみる。
statusで渡す値がおかしい場合:

$ curl -X GET "http://localhost:8000/pet/findByStatus?status=hoge" -H "accept: application/json"
{"message":"query 'status' validation failed with error: 'failed to validate item 1: matches none of the enum values'"}

パスが違う場合:

$ curl -X GET "http://localhost:8000/findByStatus?status=xxx" -H "accept: application/json"
{"message":"validation failed, path not found in api specification"}

それぞれ、なぜエラーとなったかを知るためのヒントがメッセージとして表示されたので、やはりトラシュはしやすそうだ。

所感

API SpecとあっているかをAPIデプロイ後に簡単に検証できるため、開発時にクライアント側の修正漏れを検知したりするのには便利そう。
一方で、リクエストを止めてAPI Specとリクエストを比較して検証を行うため、性能面に影響がありそうな点は気をつけた方が良さそう。
あくまでも開発時のテスト目的がメインの使用方法と捉え、本番でも使いたい人はしっかり性能試験も行った上で使うのがよいと思われる。

3
0
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
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?