Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Re-using model with different required properties

I have a path that uses complex models with almost identical properties for each http method. The problem is that I want to define some required properties for the request of PUT and POST, while no properties are required in GET response (as the server always returns all properties and its mentioned elsewhere in the documentation).

I created a simple cat API to demonstrate what I've tried. The idea is that for GET response the response model doesn't have anything marked as required, but the request of PUT must have a name for the cat.

swagger: "2.0"

info:
  title: "Cat API"
  version: 1.0.0

paths:
  /cats/{id}:
    parameters:
      - name: id
        in: path
        required: true
        type: integer
    get:
      responses:
        200:
          description: Return a cat
          schema:
            $ref: "#/definitions/GetCat"
    put:
      parameters:
        - name: cat
          in: body
          required: true
          schema:
            $ref: "#/definitions/PutCat"
      responses:
        204:
          description: Cat edited
            
definitions:
  Cat:
    type: object
    properties:
      name:
        type: string
  GetCat:
    allOf:
      - $ref: "#/definitions/Cat"
    properties:
      id:
        type: integer
  PutCat:
    type: object
    required:
      - name
    properties:
      $ref: "#/definitions/Cat/properties"

Swagger Editor says that this is a valid specification, but name is set as required for both GET and PUT. The same goes with Swagger UI.

I also tried the following version of PutCat:

PutCat:
  type: object
  required:
    - name
  allOf:
    - $ref: "#/definitions/Cat"

But now everything is optional.

I can't figure this out. Is there a way to do this properly?

EDIT:

As Helen correctly mentioned, I can use readOnly to solve this particular case with GET and PUT.

But let's say I add breed property which must be provided (in addition to the name property) for PUT. Then I add PATCH method, which can be used to update either breed or name while the other remains unchanged, and I want to set neither of those as required.

like image 566
NotNone Avatar asked Nov 28 '16 08:11

NotNone


2 Answers

In your example, you can use a single model for both GET and POST/PUT, with properties only used in the GET response marked as readOnly. From the spec:

readOnly

Declares the property as "read only". This means that it MAY be sent as part of a response but MUST NOT be sent as part of the request. Properties marked as readOnly being true SHOULD NOT be in the required list of the defined schema. Default value is false.

The spec would look like:

    get:
      responses:
        200:
          description: Return a cat
          schema:
            $ref: "#/definitions/Cat"
    put:
      parameters:
        - name: cat
          in: body
          required: true
          schema:
            $ref: "#/definitions/Cat"
      responses:
        204:
          description: Cat edited

definitions:
  Cat:
    properties:
      id:
        type: integer
        readOnly: true
      name:
        type: string
      breed:
        type: string
    required:
      - name
      - breed

This means you must PUT the name and breed:

{
  "name": "Puss in Boots",
  "breed": "whatever"
}

and GET /cats/{id} must return the name and breed and may also return the id:

{
  "name": "Puss in Boots",
  "breed": "whatever",
  "id": 5
}
like image 114
Helen Avatar answered Nov 03 '22 17:11

Helen


I've had a similar problem. Turned out that my indentation was wrong. The following syntax should work:

PutCat:
  allOf:
    - $ref: "#/definitions/Cat"
    - type: object
      required: [name]
like image 10
AlexGordon Avatar answered Nov 03 '22 15:11

AlexGordon