Skip to content

Go

The go format generates Go struct definitions with JSON tags from OpenAPI schemas.

Basic Example

OpenAPI Schema:

yaml
components:
  schemas:
    User:
      type: object
      description: A user in the system
      required:
        - id
        - email
      properties:
        id:
          type: string
          description: Unique identifier for the user
        email:
          type: string
          format: email
        name:
          type: string
        createdAt:
          type: string
          format: date-time

Generated Go:

go
// Generated by an automated build step. Do not edit.

package types

import "time"

// A user in the system
type User struct {
	// Unique identifier for the user
	ID        string     `json:"id"`
	Email     string     `json:"email"`
	Name      *string    `json:"name,omitempty"`
	CreatedAt *time.Time `json:"createdAt,omitempty"`
}

Configuration

jsonc
{
  "outputs": [
    {
      "path": "./internal/types/api.go",
      "format": "go",
      "contents": ["api:*"],
      "options": {
        "package": "types"
      }
    }
  ]
}

Options

package

Type: string
Default: "types"

The Go package name for the generated file.

jsonc
"options": {
  "package": "models"
}
go
package models

type User struct {
    // ...
}

Type Mapping

OpenAPI TypeOpenAPI FormatGo Type
string-string
stringdatestring
stringdate-timetime.Time
stringemailstring
stringuuidstring
stringbyte[]byte
integer-int
integerint32int32
integerint64int64
number-float64
numberfloatfloat32
numberdoublefloat64
boolean-bool
array-[]T
object-struct
object(no properties)map[string]any

Required vs Optional Fields

Required fields use value types, optional fields use pointers:

go
type User struct {
	ID   string  `json:"id"`           // Required
	Name *string `json:"name,omitempty"` // Optional
}

The omitempty tag is added for optional fields to exclude them from JSON when nil.

Nullable Fields

Nullable fields also use pointers:

yaml
properties:
  nickname:
    type: string
    nullable: true
go
type User struct {
	Nickname *string `json:"nickname,omitempty"`
}

JSON Tags

All fields include JSON tags with:

  • Field name in original case from OpenAPI
  • omitempty for optional/nullable fields
go
type User struct {
	FirstName *string `json:"firstName,omitempty"`
}

Enums

With generateEnums: true:

go
type UserRole string

const (
	UserRoleAdmin UserRole = "admin"
	UserRoleUser  UserRole = "user"
	UserRoleGuest UserRole = "guest"
)

With generateEnums: false:

go
type UserRole string

Date/Time Handling

The date-time format maps to time.Time:

yaml
properties:
  createdAt:
    type: string
    format: date-time
go
import "time"

type User struct {
	CreatedAt *time.Time `json:"createdAt,omitempty"`
}

The time package is automatically imported when needed.

References

References become type references:

go
type Post struct {
	Author User `json:"author"`
}

Composition

allOf (Embedding)

yaml
allOf:
  - $ref: '#/components/schemas/BaseEntity'
  - type: object
    properties:
      name:
        type: string
go
type Product struct {
	BaseEntity
	Name *string `json:"name,omitempty"`
}

oneOf / anyOf

Go doesn't have native union types. These generate interface types:

go
type Pet any // Union: Dog | Cat

For proper union handling, consider using discriminator patterns or custom unmarshaling.

Comments

Schema and property descriptions become Go comments:

go
// A user in the system
type User struct {
	// Unique identifier for the user
	ID string `json:"id"`
}

Usage Examples

JSON Marshaling

go
import (
	"encoding/json"
	"myapp/internal/types"
)

func main() {
	user := types.User{
		ID:    "123",
		Email: "user@example.com",
	}
	
	data, err := json.Marshal(user)
	if err != nil {
		panic(err)
	}
	
	fmt.Println(string(data))
	// {"id":"123","email":"user@example.com"}
}

JSON Unmarshaling

go
func parseUser(data []byte) (*types.User, error) {
	var user types.User
	if err := json.Unmarshal(data, &user); err != nil {
		return nil, err
	}
	return &user, nil
}

HTTP Handler

go
import (
	"encoding/json"
	"net/http"
	"myapp/internal/types"
)

func GetUser(w http.ResponseWriter, r *http.Request) {
	user := types.User{
		ID:    "123",
		Email: "user@example.com",
	}
	
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(user)
}

Limitations

No Namespaces

Go format doesn't support namespaces. Use separate packages instead:

jsonc
"outputs": [
  { 
    "path": "./internal/types/users/types.go",
    "format": "go",
    "contents": ["users:*"],
    "options": { "package": "users" }
  },
  {
    "path": "./internal/types/products/types.go",
    "format": "go",
    "contents": ["products:*"],
    "options": { "package": "products" }
  }
]

Validation

Generated structs are for serialization only. For validation, use:

Union Types

Go lacks native union types. Options:

  • Use any (loses type safety)
  • Implement custom UnmarshalJSON
  • Use discriminator fields

Best Practices

Package Organization

internal/
  types/
    api/
      types.go     # Generated
      helpers.go   # Custom helpers
    types.go       # Re-exports

Custom Methods

Add methods in a separate file to avoid overwriting:

go
// internal/types/api/helpers.go
package api

func (u *User) FullName() string {
	if u.Name != nil {
		return *u.Name
	}
	return u.Email
}

Validation Tags

Add validation after generation:

go
// Extend generated types with validation
type ValidatedUser struct {
	User
}

func (u *ValidatedUser) Validate() error {
	if u.Email == "" {
		return errors.New("email is required")
	}
	return nil
}

See Also

Released under the MIT License.