👻

FreeFormatなJSONをREST APIのパラメータとして扱う

2021/02/18に公開

Java、Swagger、SpringBootを利用した構成で、REST APIのパタメータとしてFreeFormatなJSONを扱う方法を記載します

swagger.yamlで動的なJSONを表現する

definitions:
  Product:
    type: "object"
    additionalProperties:
      type: object

additionalPropertiesを追加することで、自動生成したJavaコードではProductの型がHashMap<String, Object>となりJSONのKey、Valueと同等な感じで扱えるようになります

APIでどう扱うか

GET APIでパスパラメータとしてフリーフォーマットなJSONを文字列で受け取り処理する

objectMapper.readValueでSwaggerで自動生成されたProduct.classにマッピングできる

@Override
public ResponseEntity<Response> find(
      @Valid String query,
      @Valid Integer offset,
      @Valid Integer limit
  ) {
Response res =  new Response();
List<Product> products = new ArrayList<>();

// queryはデータ取得処理でそのまま使う
// データ取得処理で何かしら配列のオブジェクトを入手

for (Hoge product : datalist) { // ここはDBによってloopの回し方変わりそう
  // HogeをjsonStrにする処理をここに書く
  products.add(objectMapper.readValue(new StringReader(jsonStr), Product.class));
}

res.setProducts(products);
return ResponseEntity.ok(res);

POST APIでBodyとしてフリーフォーマットなJSONを受け取り処理する

リクエストの想定

$ curl -XPOST localhost:8080/products \
  -H "Content-Type: application/json" \
  -d '{"device":["ps4","pc"],"title": "hogeGame","info": {"x": 2, "y": 1}}'

リクエスト時にbodyにフリーフォーマットなJSONを要求、insertメソッドではMap<String, Object> bodyにコンバートされ、以下の例ではJSON文字列に加工している

@Override
public ResponseEntity<Void> insert(@Valid Map<String, Object> body) {
  String insertQuery = getObjectMapper().get().writeValueAsString(body);

swagger例

swagger.yaml

~~ 略 ~~
paths:
  /product:
    get:
      parameters:
      - name: "query"
        in: "query"
        required: false
        type: "string"
      - name: "offset"
        in: "query"
        required: false
        type: "integer"
      - name: "limit"
        in: "query"
        required: false
        type: "integer"
      responses:
        "200":
          schema:
            $ref: "#/definitions/Response"
    post:
      parameters:
      - name: "document"
        in: "body"
        required: true
        schema:
            $ref: "#/definitions/Product"
~~ 略 ~~
definitions:
  Product:
    type: "object"
    additionalProperties:
      type: object
  Response:
    type: "object"
    properties:
      products:
        type: "array"
        items:
          $ref: "#/definitions/Product"
      offset:
        type: "integer"
      limit:
        type: "integer"

Discussion