Swagger の拡張メモ その2

neuecc/LightNode · GitHub が新しい Swagger UI に対応したっていうのを見かけたので、こっちも見直してみようかなと。 *1

Swagger 拡張のメモ - お だ のスペースからの変わった点のメモ。

Swagger のバージョンを 1.5.2-M1 から 1.5.0 にしました。*2

  • 大きな変更点は、パッケージが変わりました。合わせて Maven Repository の GroupId も変わっているので注意!
    com.wordnik から io.swagger になっています。

  • @DefaultValue に対応しています。 io.swagger.jaxrs.ParameterProcessor クラスが追加され、そこで Parameter に付与されているアノテーションに対し色々処理するようになっています。
    ParameterProcessor#applyAnnotations が static メソッドのため、拡張出来ないのが難点。。
    ここ拡張出来ると自前アノテーションの処理が大分楽になりそうなのに。
    ちなみに @BeanParam は対応していません。

  • @ApiResponse に responseContainer が追加されている。 但し、responseContainer を指定した場合、Swagger UI で表示してくれない。
    Swagger UI で表現出来るような JSON 出力になっていない?*3

  • @Api#description が Deprecated になってた。 代わりは、@SwaggerDefinition を使ってください。

@Path("/sample")
@Api(value="/sample", description="サンプル")
@RequestScoped
public class SampleResource {
...
}

こんな風に変更する

@Path("/sample")
@Api(value="/sample")
@SwaggerDefinition(tags={@Tag(name="sample", description="サンプル"})
@RequestScoped
public class SampleResource {
...
}

新しいメモ

Swagger UI では BodyParameter の時は、JSONXML を入力出来るようになっています。
で、Model Schema をクリックすると、入力欄に example の値がコピーされる機能があります。

これを BodyParameter で無い時もやりたくて色々調べてみました。

吐かれる JSON の Parameter に "schema" があって、"in" が "body" の時、このUIになります。
http://petstore.swagger.io/v2/swagger.json の /pet Post から抜粋。

"parameters":[
  {
    "in":"body",
    "name":"body",
    "description":"Pet object that needs to be added to the store",
    "required":true,
    "schema":{
      "$ref":"#/definitions/Pet"
    }
  }
],

"in" が "body" で "schema" があれば、他の Parameter があっても大丈夫でした。

"parameters":[
  {
    "name":"name",
    "in":"query",
    "required":false,
    "type":"string"
  },
  {
    "name":"id",
    "in":"formData",
    "required":false,
    "type":"number",
    "format":"double"
  },
  {
    "name":"qty",
    "in":"formData",
    "required":false,
    "type":"string"
  },
  {
    "in":"body",
    "name":"hoge",
    "required":false,
    "schema":{
      "type":"array",
      "items":{
        "$ref":"#/definitions/ParamBean"
      }
    }
  }

こんな感じの JSON を食わしてもちゃんと出してくれます。
が、Parameter Type が "body" になるのは何か嫌。

なので、swagger-ui.js をちょっといじると "in" が "body" で無くても同じような感じで表示してくれます。

@@ -1958,7 +1958,7 @@ Resolver.prototype.resolve = function (spec, arg1, arg2, arg3) {
           var parameter = parameters[i];
           location = '/paths' + name + '/' + method + '/parameters';
 
-          if (parameter.in === 'body' && parameter.schema) {
+          if (parameter.schema) {
             this.resolveTo(root, parameter.schema, resolutionTable, location);
           }
 
@@ -31901,7 +31901,7 @@ SwaggerUi.Views.ParameterView = Backbone.View.extend({
 
     this.model.type = type;
     this.model.paramType = this.model.in || this.model.paramType;
-    this.model.isBody = this.model.paramType === 'body' || this.model.in === 'body';
+    this.model.isBody = this.model.paramType === 'body' || this.model.in === 'body' || !(typeof schema === 'undefined');
     this.model.isFile = type && type.toLowerCase() === 'file';

parameter に schema があったら body 扱いするような感じですね。

あとは、JSON

"parameters":[
  {
    "name":"name",
    "in":"query",
    "required":false,
    "type":"string"
  },
  {
    "name":"id",
    "in":"formData",
    "required":false,
    "type":"number",
    "format":"double"
  },
  {
    "name":"qty",
    "in":"formData",
    "required":false,
    "type":"string"
  },
  {
    "in":"formData",
    "name":"hoge",
    "required":false,
    "schema":{
      "type":"array",
      "items":{
        "$ref":"#/definitions/ParamBean"
      }
    }
  }

てな感じに吐けるように、カスタムの Parameter クラスを作成します。
実装は io.swagger.models.parameters.BodyParameter を参考に in だけ書き換えれるようにするだけで取り敢えずは問題無し。
んで、QueryParameter や FormParameter 等から 作成したカスタムのParameterに差し替えればOK。
差し替える場所は SwaggerExtension でやるなり、Reader で読んだ Swagger インスタンスに対してするなりお好きな方で。
SwaggerExtension でやるなら、目印用の自作アノテーション付けないと難しいかな。
自作アノテーション使うなら、ParameterProcessor#applyAnnotations が拡張出来たら良いのになぁ。

*1:ちなみに LightNode は面白そうなんですが使ってません。.NET 書く機会が最近無くて。。

*2:1.5.2-M1 の方が新しいように見えますが、1.5.0 が最新版です

*3:未調査