Skip to main content

Introducing oneOf and anyOf Support in Go

· 5 min read

We have introduced support for oneOf and anyOf types in our Go SDKs.

Details

In OpenAPI, any request parameter or response payload could use union types i.e. oneOf/anyOf, which provides the flexibility of accepting different types of request parameters and returning various types of response payload. Here is an example of an API call using union types.

paths:
 /send/combined:
    post:
      summary: Send Combined
      operationId: SendCombined
      requestBody:
        required: true
        content:
          application/json:
            schema:
              oneOf:
                - $ref: '#/components/schemas/Car'
                - $ref: '#/components/schemas/Morning'
                - $ref: '#/components/schemas/Atom'

      responses:
        '200':
          description: Send Combined successfully
          content:
            application/json:
              schema:
                anyOf:
                - type: integer
                  format: int32
                - $ref: '#/components/schemas/Atom'
                - nullable: true
...

The API call, shown in the OpenApi format above, is a post-call that takes in either Car, Morning, or Atom as request payload. Previously, union types were not supported therefore the endpoint was expecting the combined schema object map[string]interface{} as a parameter. Here is how the parameter initialization would look like when calling the endpoint.

sendCombinedBody := models.SendCombinedBodyContainer.
    FromCar(models.Car{
        HaveTrunk: true,
        Vehicle: models.Vehicle{
            NumberOfTyres: "4",
        },
    })

apiResponse, err := senderController.SendCombined(ctx, sendCombinedBody)

Now, we have containers that can hold different types of data combined. With these containers, you can check what type of data is inside using the functions.

apiResponse, err := senderController.SendCombined(ctx, sendCombinedBody)

if atom, isAtom := apiResponse.Data.AsAtom(); isAtom {
   
    fmt.Println(atom)

} else if number, isNumber := apiResponse.Data.AsNumber(); isNumber {

    fmt.Println(number)

}

In the above code snippet, SendCombined will return either an Atom or Number instance as the response payload. Previously, it was considered as an interface{} object response which allowed any type of response payload. Now, with the introduction of oneOf and anyOf support, we can validate that the response can be either Atom or Number.

What has Changed?

The Go SDK now can handle union types in an endpoint's request and response. The type validation for union types is also added to support the oneOf/anyOf constraints.

Introducing Containers

Container types are introduced in the Go SDK to manage union types. The union types cases are contained in a container, and their marshaling and un-marshaling are also handled in the same container. This container type exposes the From<#CaseName> method to set the case value and As<#CaseName> methods to retrieve type converted values, respectively.

Changes in Models

Now, every model type has an internal validate() function for all the required properties to verify that required properties are present in the model.

Changes in Endpoints

Endpoint Doc Changes

The endpoint's doc string has been updated to describe union-type parameters or return types.

// SendCombined takes context, sendCombinedBody as parameters and
// returns a model.ApiResponse with *models.MixedParamResponse data and
// an error if there was an issue with the request or response.
func (s *SenderController) SendCombined(
    ctx context.Context,
    sendCombinedBody models.SendCombinedBody) (
    models.ApiResponse[*models.MixedParamResponse],
    error)

README Changes

Now, the Go SDK README will reflect the support for union types in parameter types or response types.

readme_after