Search code examples
swaggeropenapi-generator

Default Object Parameter in swagger


I don't understand default values for object parameters in swagger. The documentation doesn't seem to have any examples.

For example:

components:
  parameters:
    coordinates:
      in: query
      name: coordinates
      description: Test Obj Parameter
      schema:
        type: object
        properties:
          lat:
            type: number
            default: 0.0
          long:
            type: number
            default: 0.0
      required: false

paths:
  /my/path/:
    get:
      parameters:
        - $ref: "./common.yaml#/components/parameters/coordinates"
  1. I assume I can define default: [51.47, 0.0] in the path's parameters section?
  2. If all member fields are optional, and the parameter itself is optional, do I need to specify a default value in the path's parameters? If I don't and the user calls the endpoint without providing a value would the back end get the coordinates 0, 0 ?

The code that's generated with default: [51.47, 0.0] , default: {"lat":51.4, "lon":0.0} and with no default specified is the same.

Making one of the member fields required seems to only add a isSet flag, setteng and unsetter functions.


Solution

  • There are a few different questions here, so I'm going to split them up into three topics

    1. Where can I find an example of a valid schema with parameters that define default values?
    2. Can I define the default values in the path's parameters section?
    3. If parameters and member fields are optional, does the default value need to be declared?

    Disclaimer: You didn't provide any generator commands, so I am using the gradle-plugin with the spring generator for most of my examples. I can update this to use a different plugin or generator if you are unable to get your code working with what I provide.

    Where can I find examples?

    The swagger documentation for parameters has a section called Default Parameter Values. In that section, the documentation states

    "Use the default keyword in the parameter schema to specify the default value for an optional parameter. The default value is the one that the server uses if the client does not supply the parameter value in the request. The value type must be the same as the parameter’s data type."

    It also has the following example:

     parameters:
            - in: query
              name: offset
              schema:
                type: integer
                minimum: 0
                default: 0
              required: false
              description: The number of items to skip before starting to collect the result set.
            - in: query
              name: limit
              schema:
                type: integer
                minimum: 1
                maximum: 100
                default: 20
              required: false
              description: The number of items to return.
    

    The coordinates schema you provided in your question is a valid schema. I even went so far as to test it in my own generator, using the spring generator, and I was able to get a valid object created. This object had the below fields defined:

    @JsonProperty("lat")
    private BigDecimal lat = new BigDecimal("0.0");
    
    @JsonProperty("long")
    private BigDecimal _long = new BigDecimal("0.0");
    

    As you can see, the default values were defined as expected.

    Can I define the default values in the path's parameters section?

    Plainly speaking, no. The swagger documentation states:

    Any sibling elements of a $ref are ignored. This is because $ref works by replacing itself and everything on its level with the definition it is pointing at.

    Consider the following schema:

    components:
      schemas:
        EmployeeInfo:
          type: object
          properties:
            name:
              description: an employee's name
              $ref: '#/components/schemas/Name'
            address:
              $ref: '#/components/schemas/Address'
              description: an employee's address
        CustomerInfo:
          type: object
          properties:
            name:
              description: a customer's name
              $ref: '#/components/schemas/Name'
            address:
              $ref: '#/components/schemas/Address'
              description: a customer's address
        Name:
          description: a standard name
          type: object
          properties:
            firstName:
              type: string
            lastName:
              type: string
        Address:
          description: a standard address
          type: object
          properties:
            street:
              type: string
            city:
              type: string
            state:
              type: string
            zip:
              type: string
    

    This schema appears valid, and will pass most validation tools. However, if we look at the employee info object in our swagger-ui, we will see that the descriptions for the name and address ignore the description in the schema. Swagger ui image

    This is because, as the documentation states, anything else contained at the same level as the $ref is ignored.

    The same is true for any defaults you try to set at the path level. If you are referencing a schema contained elsewhere, than the default values will be ignored.

    Do I have to declare a default value?

    This is more of a style choice, and falls back to the age old answer: "it depends". Remember that swagger-ui is in part a REST interface, but is also your documentation. What are you doing with these coordinates? What happens if the users don't supply them? What is expected to happen? Does providing them or not providing them change your APIs response schema?

    Most importantly, do you want your users to know of the coordinates default values?

    For example, you can easily add a method in your controller that sets the values to something if they are not provided in the request. You don't have to tell your users about this. This would be a default value without documentation. If you want to tell your users about it, you can set an example and a description that explains the default value.

    If the value is required, I personally prefer to make the users provide it. This ensures they know what they are requesting and what they are getting. If the value is optional, it all comes down to style and documentation. I prefer explaining the usage to my users, so I will document the default so they are aware of how it is being used. This will also result in fields being set automatically, such as in the Java code above.


    Updated to show use of examples instead of default values

    Here's a yaml using examples in parameters. You can copy and paste it into swagger editor to see how it renders and displays. When choosing an example to view, notice that the description changes. Also notice that when you click try it out, it will create a request using the example (with the values you have provided in the example:

    openapi: 3.0.3
    info:
      title: My-API
      version: 0.0.1
    servers:
      - url: 'https://my.server.com'
    paths:
      /employees:
        get:
          tags:
            - Employees
          summary: Add a new article to the store
          description: Get an Object
          operationId: getObject
          parameters:
            - $ref: '#/components/parameters/employeeInfo'
          responses:
            '200':
              description: Successful operation
    components:
      parameters:
        employeeInfo:
          name: employee
          in: query
          description: The information of the employee
          required: false
          schema:
            $ref: '#/components/schemas/EmployeeInfo'
          examples:
            Employee Information:
              value:
                name: Bob Smith
                title: Front Desk
                responsibilities:
                  - working
                  - playing
                phone: (123) 555-1234
              description: |
                This is a description of the manager item.
                you can explain default values here.
                
                For example:
                
                **Parameters**:
                * **title**: 
                  * defaults to Night Manager if not provided
                  * Any String is valid, but may return status 404 if the title is not a valid title after validation
                * **name**:
                  * no default value
    
            Manager Information:
              value:
                name: Kevin Mitchell
                title: Night Manager
                responsibilities:
                  - watch Bob
                  - don't sleep
              description: |
                This is a description of the manager item.
                you can explain default values here.
                
                For example:
                
                **Parameters**:
                * **title**: 
                  * defaults to Night Manager if not provided
                  * Any String is valid, but may return status 404 if the title is not a valid title after validation
                * **name**:
                  * no default value
                  * must be a valid employee name
    
      schemas:
        EmployeeInfo:
          description: general employee information
          type: object
          properties:
            name:
              type: string
            phone:
              type: string
              pattern: '^(\([0-9]{3}\) |[0-9]{3}-)[0-9]{3}-[0-9]{4}$'
            id:
              type: string
              format: uuid
          oneOf:
            - $ref: '#/components/schemas/ManagementInfo'
            - $ref: '#/components/schemas/GruntInfo'
            
        GruntInfo:
          type: object
          properties:
            responsibilities:
              $ref: '#/components/schemas/EmployeeResponsibilities'
        ManagementInfo:
          type: object
          properties:
            name:
              type: string
              default: Bob
            title:
              type: string
              default: Manager
            responsibilities:
              $ref: '#/components/schemas/ManagerResponsibilities'
        ManagerResponsibilities:
          description: manager responsibilities
          type: array
          items:
            type: string
            enum:
              - Meetings
              - Sleeping
              - Planning
              - Rehersing
              - Supervising
          default:
            - meetings
            - sleeping
        EmployeeResponsibilities:
          title: Employee Responsibilities
          description: Employee responsibilities
          type: array
          items:
            type: string
            enum:
              - cleaning
              - organizing
              - attending
          default:
            - cleaning
    

    You can now see that each example is available in the drop-down, along with the description of the values.

    Examples with descriptions

    If you click try it out on the employee example, it will create the following request: https://my.server.com/employees?name=Bob%20Smith&title=Front%20Desk&responsibilities=working&responsibilities=playing&phone=%28123%29%20555-1234