Follow Us

How to implement request validation with OAPI-Codegen and Go for robust development

Several of our projects require back-end as well as front-end work. If a client wants us to create RESTful APIs, we start by using the OpenAPI 3 specification. We write the server code using a tool called oapi-codegen. This article explains how we do it and add special tags to parts of our Go code, such as validate tags.

The basic API specification

A lot of articles begin by exploring the history of the tools they discuss. Let's skip the traditional introduction and get started. At first, the API specification can be summarized as follows:

openapi: "3.0.0"
info:
  version: 1.0.0
  title: API
servers:
  - url: http://localhost:8080/api/v1/something
paths:
  /:
    post:
      tags: ["createSomething"]
      operationId: createSomething
      parameters:
        - $ref: '#/components/parameters/xForwardedFor'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateSomethingRequest'
      responses:
        '200':
          description: uuid of the created entity
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UUIDResponse'
        '401':
          description: unauthorized
        '403':
          description: forbidden
        '404':
          description: not found
        '500':
          description: internal server error

components:
  schemas:
    CreateSomethingRequest:
      type: object
      required:
        - something
      properties:
        something:
          type: number
          example: 1
          x-oapi-codegen-extra-tags:
            validate: gte=0
    UUIDResponse:
      type: object
      required:
        - uuid
      properties:
        uuid:
          type: string
          format: uuid
  parameters:
    xForwardedFor:
      in: header
      name: X-Forwarded-For
      schema:
        type: string
      required: true
      x-oapi-codegen-extra-tags:
        validate: ipv4

This API consists of 1 POST request. As a request body, it has the CreateSomethingRequest schema. We also have a header called xForwardedFor. If you look at the definition, CreateSomethingRequest.something and xForwardedFor properties have a custom property called x-oapi-codegen-extra-flag. This allows you to add extra tags to your generated struct fields. As all request bodies require validation, we chose validate.

Now let's generate the code...

$ oapi-codegen -package main -generate types api/api.yml > openapi_types.gen.go

The generated code should like this:

// CreateSomethingRequest defines model for CreateSomethingRequest.
type CreateSomethingRequest struct {
   Something float32 `json:"something" validate:"gte=0"`
}
...

// CreateSomethingParams defines parameters for CreateSomething.
type CreateSomethingParams struct {
   XForwardedFor XForwardedFor `json:"X-Forwarded-For" validate:"ipv4"`
} 

It's great to see our fields have validate tags. Now we can begin the validation process!

var (
   _ ServerInterface = HTTPServer{}
)

type HTTPServer struct {
   ...
}
func (h HTTPServer) CreateSomething(w http.ResponseWriter, r *http.Request, params CreateSomethingParams) {
   validate := validator.New()
   err := validate.Struct(params)
   if err != nil {
      errValidation := err.(validator.ValidationErrors)
      // your implementation
   }
}

The final result should look similar to what you see here, even though this is just an illustration.

Author: Csaba Ujvári


wave

Leave a Message

Contact us to start building your business together!

Contact Us