LIGHT

  • News
  • Docs
  • Community
  • Reddit
  • GitHub

Swagger 2.0 Specification Best Practices

Swagger 2.0 specification is a very loose specification that gives designer many options to write the spec. In most cases, developers write the code with annotations and generate the specification afterward. With an enterprise scale in mind, we encourage a design first approach. The outcome is not just a document but a specification that can be used to scaffold a new project and loaded during runtime to verify JWT scopes for security and validate requests to protect the business layer against attacks.

To enable light-codegen to generate meaningful code and utilize the full potential of the light-rest-4j framework, the author of the OpenAPI 3.0 specification should follow the best practices below.

Guidelines

  • clear and easily readable by architects, analysts, developers
  • well documented, with explanations provided in description tags
  • adheres to OpenAPI specifications - v2.0 at the time of this writing
  • uses a design which lends itself to a clean and easily consumable object model

Security First

Often API designers focus on functionalities and add security later on. We would encourage to follow security first approach so that security is considered for every endpoint during the design.

Before working on a new specification, you can copy from an existing one and petstore is a good starting point. There are also other Swagger specifications in the model-config repository to help you in learning the design style.

Within petstore specification you can find the following block that defines the security under the component. This section is optional in the specification, but here it is mandatory. light-codegen throws an error if securityDefinitions are not found.

securityDefinitions:
  petstore_auth:
    type: oauth2
    authorizationUrl: 'http://petstore.swagger.io/oauth/dialog'
    flow: implicit
    scopes:
      'write:pets': modify pets in your account
      'read:pets': read your pets

Once the securityDefinitions is defined, you can specify security scopes for each endpoint. When you add a new endpoint you might ask yourselves a question. Do I need to create a brand new scope or pick one or more existing scopes from the scopes defined in securityDefinitions?

The endpoint/operation definition with security definition looks like this.

    delete:
      tags:
        - pet
      summary: Deletes a pet
      description: ''
      operationId: deletePet
      produces:
        - application/xml
        - application/json
      parameters:
        - name: api_key
          in: header
          required: false
          type: string
        - name: petId
          in: path
          description: Pet id to delete
          required: true
          type: integer
          format: int64
      responses:
        '400':
          description: Invalid ID supplied
        '404':
          description: Pet not found
      security:
        - petstore_auth:
            - 'write:pets'
            - 'read:pets'

Above design ensures that the light-rest-4j framework compares the scopes from JWT token against the scopes defined for each endpoint at runtime. It gives you the flexibility to grant permissions based on endpoints to consumers.

Definitions

In the specification, models define what would be the request/response body for each endpoint. There are two different places to define models. Flattened/scattered in each endpoint or extracted into the definitions.

When the model definition scattered in each endpoint, there is no name and the same model might be duplicated in several endpoints. The generator does not generate POJO classes as it does not make sense to generate some classes named body0, body1, body2, etc. Chances are body0 is for get request, and body2 is for put request. As both of them are dealing a same set of attributes, they are the same. How would developers remember that in your get handler, you should use body0 but in your put handler, you should use body2? They would be shocked when they found that these two classes have the same fields and methods except the class names are different.

To generate POJO classes with proper names and to avoid duplications, it is best to extract common data objects into the definitions section.

Here is an example in the petstore specification.

definitions:
  Order:
    type: object
    properties:
      id:
        type: integer
        format: int64
      petId:
        type: integer
        format: int64
      quantity:
        type: integer
        format: int32
      shipDate:
        type: string
        format: date-time
      status:
        type: string
        description: Order Status
        enum:
          - placed
          - approved
          - delivered
      complete:
        type: boolean
        default: false
    xml:
      name: Order

The above Order definition is used to generate a Java class called Order in light-codegen. With Order is defined, you can put $ref in each point for object definition. Here is an example response that utilizes the Order definition.

  /store/order:
    post:
      tags:
        - store
      summary: Place an order for a pet
      description: ''
      operationId: placeOrder
      produces:
        - application/xml
        - application/json
      parameters:
        - in: body
          name: body
          description: order placed for purchasing the pet
          required: true
          schema:
            $ref: '#/definitions/Order'
      responses:
        '200':
          description: successful operation
          schema:
            $ref: '#/definitions/Order'
        '400':
          description: Invalid Order

Here is another response example with an array.

  /user/createWithArray:
    post:
      tags:
        - user
      summary: Creates list of users with given input array
      description: ''
      operationId: createUsersWithArrayInput
      produces:
        - application/xml
        - application/json
      parameters:
        - in: body
          name: body
          description: List of user object
          required: true
          schema:
            type: array
            items:
              $ref: '#/definitions/User'
      responses:
        default:
          description: successful operation

Examples

Swagger specification gives you an opportunity to define an example response for each endpoint so that your API consumer can easily understand what would be expected when the endpoint is accessed. Also, light-codegen has a feature to generate mock responses based on the examples defined in the specification. Once you have examples defined, the generated project can be built and started with mock responses for consumers to start their work immediately without waiting for the provider to complete the API implementation.

For more details on this topic, please refer to Swagger 2.0 Mock.

Naming Convention

As definition name is translated into Java class name, it is better to follow the naming convention of Java.

  • Elements should always start with an upper-case letter, to respect class definitions in generated code, which always start with an upper-case letter
  properties:
     error:
       $ref: 'org/APIERR0001/1.0.1/errors.yaml#/error'
  ...
  vs
  ...
  properties:
    error:
      $ref: 'org/APIERR0001/1.0.1/errors.yaml#/Error'
  • Elements should use only alpha-numeric characters and avoid underscores, @ signs or others. OpenAPI general guidelines recommend alpha-numeric only, and, while these would generate correct programming language code, it would break accepted programming guidelines.
  "@nameID":
    $ref: "org/APIDOMAIN0001/0.0.5/elementDefs.yaml#/NameID"
  "@accessCode":
    $ref: "org/APIDOMAIN0001/0.0.5/elementDefs.yaml#/Access_Code"
...
  filterList:
     type: array
     items:
       $ref: "org/APIDOMAIN0001/0.0.5/elementDefs.yaml#/APIFilter_Type"
...
vs
...
  nameID:
    $ref: "org/APIDOMAIN0001/0.0.5/elementDefs.yaml#/NameID"
  accessCode:
    $ref: "org/APIDOMAIN0001/0.0.5/elementDefs.yaml#/AccessCode"
...
  filterList:
    type: array
    items:
      $ref: "org/APIDOMAIN0001/0.0.5/elementDefs.yaml#/APIFilterType"    

Object definitions are to be avoided from the declaration of Body elements

The objects should be moved to the definitions section of the specification or in an external document, for shared definitions.

The Body should not contain any declarations as in “type: object”.

Ex.: selection element:

Original version:

  ...
  selection:
    description:  Identifies the selection to retrieve information for. Only one of the child elements of this structure are to be provided.
    type: object
    properties:
      id:
        $ref: "org/APIDOMAIN0001/0.0.1/elementDefs.yaml#/ID"
      card:
        $ref: "org/APIDOMAIN0001/0.0.1/elementDefs.yaml#/AlternativeID"
  ...      

Updated version:

...
  selection:
    $ref: "#/definitions/Selection"
  ...
  definitions:
  # Selection structures.
    Selection:
      type: object
      description:  Identifies the selection to retrieve information for. Only one of the child elements of this structure are to be provided.
      properties:
        id:
          $ref: "org/APIDOMAIN0001/0.0.2/elementDefs.yaml#/ID"
        card:
          $ref: "org/APIDOMAIN0001/0.0.2/elementDefs.yaml#/AlternativeID"
  ...

Implicit object definitions are to be avoided from the declaration of Body elements when used from collection declarations

An object should be defined in the definitions section of the specification or an external document, for shared definitions, and be referenced from the collection in the Body, instead of the declaration of an implicit object.

The Body should not contain any collection declarations with implicit object definitions; the equivalent of Java inline declarations.

Ex.: names element:

Original version:

  ...
  names:
    description: Contact information.
    type: array
    items:
      properties:
        "id":
          $ref: "org/APIDOMAIN0001/0.0.1/elementDefs.yaml#/ID"
        name:
          description: A name can contain up to two lines of name information.
          type: array
          items:
            $ref: "org/APIDOMAIN0001/0.0.1/elementDefs.yaml#/Name"
  ...          

Updated version:

...
  names:
    type: array
    items:
      $ref: "#/definitions/RetrieveNames"
  ...
  definitions:
  RetrieveNames:
    description: Contact information
    type: object
    properties:
      id:
        $ref: "org/APIDOMAIN0001/0.0.2/elementDefs.yaml#/ID"
      name:
        description: A name can contain up to two lines of name information.
        type: array
        items:
          $ref: "org/APIDOMAIN0001/0.0.2/elementDefs.yaml#/Name"
  ...
  • About Light
    • Overview
    • Testimonials
    • What is Light
    • Features
    • Principles
    • Benefits
    • Roadmap
    • Community
    • Articles
    • Videos
    • License
    • Why Light Platform
  • Getting Started
    • Get Started Overview
    • Environment
    • Light Codegen Tool
    • Light Rest 4j
    • Light Tram 4j
    • Light Graphql 4j
    • Light Hybrid 4j
    • Light Eventuate 4j
    • Light Oauth2
    • Light Portal Service
    • Light Proxy Server
    • Light Router Server
    • Light Config Server
    • Light Saga 4j
    • Light Session 4j
    • Webserver
    • Websocket
    • Spring Boot Servlet
  • Architecture
    • Architecture Overview
    • API Category
    • API Gateway
    • Architecture Patterns
    • CQRS
    • Eco System
    • Event Sourcing
    • Fail Fast vs Fail Slow
    • Integration Patterns
    • JavaEE declining
    • Key Distribution
    • Microservices Architecture
    • Microservices Monitoring
    • Microservices Security
    • Microservices Traceability
    • Modular Monolith
    • Platform Ecosystem
    • Plugin Architecture
    • Scalability and Performance
    • Serverless
    • Service Collaboration
    • Service Mesh
    • SOA
    • Spring is bloated
    • Stages of API Adoption
    • Transaction Management
    • Microservices Cross-cutting Concerns Options
    • Service Mesh Plus
    • Service Discovery
  • Design
    • Design Overview
    • Design First vs Code First
    • Desgin Pattern
    • Service Evolution
    • Consumer Contract and Consumer Driven Contract
    • Handling Partial Failure
    • Idempotency
    • Server Life Cycle
    • Environment Segregation
    • Database
    • Decomposition Patterns
    • Http2
    • Test Driven
    • Multi-Tenancy
    • Why check token expiration
    • WebServices to Microservices
  • Cross-Cutting Concerns
    • Concerns Overview
  • API Styles
    • Light-4j for absolute performance
    • Style Overview
    • Distributed session on IMDG
    • Hybrid Serverless Modularized Monolithic
    • Kafka - Event Sourcing and CQRS
    • REST - Representational state transfer
    • Web Server with Light
    • Websocket with Light
    • Spring Boot Integration
    • Single Page Application
    • GraphQL - A query language for your API
    • Light IBM MQ
    • Light AWS Lambda
    • Chaos Monkey
  • Infrastructure Services
    • Service Overview
    • Light Proxy
    • Light Mesh
    • Light Router
    • Light Portal
    • Messaging Infrastructure
    • Centralized Logging
    • COVID-19
    • Light OAuth2
    • Metrics and Alerts
    • Config Server
    • Tokenization
    • Light Controller
  • Tool Chain
    • Tool Chain Overview
  • Utility Library
  • Service Consumer
    • Service Consumer
  • Development
    • Development Overview
  • Deployment
    • Deployment Overview
    • Frontend Backend
    • Linux Service
    • Windows Service
    • Install Eventuate on Windows
    • Secure API
    • Client vs light-router
    • Memory Limit
    • Deploy to Kubernetes
  • Benchmark
    • Benchmark Overview
  • Tutorial
    • Tutorial Overview
  • Troubleshooting
    • Troubleshoot
  • FAQ
    • FAQ Overview
  • Milestones
  • Contribute
    • Contribute to Light
    • Development
    • Documentation
    • Example
    • Tutorial
“Swagger 2.0 Specification Best Practices” was last updated: July 5, 2021: fixes #275 checked and corrected grammar/spelling for majority of pages (#276) (b3bbb7b)
Improve this page
  • News
  • Docs
  • Community
  • Reddit
  • GitHub
  • About Light
  • Getting Started
  • Architecture
  • Design
  • Cross-Cutting Concerns
  • API Styles
  • Infrastructure Services
  • Tool Chain
  • Utility Library
  • Service Consumer
  • Development
  • Deployment
  • Benchmark
  • Tutorial
  • Troubleshooting
  • FAQ
  • Milestones
  • Contribute