Skip to content
kolahPublic

About

Eugene - OpenAPI INterface Kit 🐷

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

Β 

History

27 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Eugene - OpenAPI INterface Kit - oink! 🐷

Eugene is a CLI tool for generating Go code from OpenAPI specifications (3.0, 3.1, 3.2). It generates type-safe clients, servers, and type definitions from your API specs.

This project is heavily inspired by oapi-codegen/oapi-codegen and is an attempt to bring newest OpenAPI specifications while offering similar code generation experience.

Underneath, the tool is built upon pb33f/libopenapi that made creating this tool possible.

Installation

go install github.com/kolah/eugene/v2/cmd/eugene@latest

or use it as a tool dependency:

go get -tool github.com/kolah/eugene/v2/cmd/eugene@latest

Quick Start

  1. Create a configuration file eugene.yaml:
spec: ./api/openapi.yaml

go:
  package: api
  output-dir: ./gen
  targets:
    - types
    - server
    - client
  1. Run the generator:
eugene generate go

Or generate specific targets:

eugene generate go types
eugene generate go server
eugene generate go all

CLI Usage

eugene generate go [target] [flags]

Targets:
  types          Generate Go type definitions
  server         Generate Go server code
  strict-server  Generate Go strict server with typed responses
  client         Generate Go HTTP client
  spec           Generate embedded OpenAPI spec
  all            Generate all targets

Common Flags:
  -c, --config string              Config file (default: eugene.yaml)
  -s, --spec string                OpenAPI spec path
      --templates string           Custom templates directory
      --exclude-schemas strings    Schemas to exclude
      --include-tags strings       Tags to include (exclusive)
      --exclude-tags strings       Tags to exclude
      --dry-run                    Print output without writing files

Go Flags:
  -o, --output-dir string          Output directory
  -p, --package string             Go package name
  -f, --server-framework string    Server framework: echo, chi, stdlib
      --enum-strategy string       Enum strategy: const, type, struct
      --uuid-package string        UUID type: string, google, gofrs
      --nullable-strategy string   Nullable strategy: pointer, nullable
      --allof-strategy string      AllOf strategy: embed, flatten
      --enable-yaml-tags           Generate yaml tags alongside json tags
      --additional-initialisms     Custom initialisms for naming (e.g., GTIN,SKU)

Configuration

Eugene supports configuration via YAML file, CLI flags, and environment variables. Loading order: defaults -> YAML file -> CLI flags.

Full Configuration Example

spec: api/openapi.yaml

templates:
  dir: ./custom-templates

exclude-schemas:
  - InternalType

include-tags:
  - public

go:
  package: api
  output-dir: ./gen
  server-framework: echo

  targets:
    - types
    - server
    - strict-server
    - client
    - spec

  types:
    enum-strategy: const      # const, type, or struct
    uuid-package: google      # string, google, or gofrs
    nullable-strategy: pointer # pointer or nullable
    allof-strategy: embed      # embed or flatten

  output-options:
    enable-yaml-tags: true
    additional-initialisms:
      - GTIN
      - SKU

  import-mapping:
    "#/components/schemas/Error": github.com/myorg/api/common

Generated Code

Types (types.go)

Generates Go structs from OpenAPI schemas:

type Pet struct {
    ID   int64  `json:"id"`
    Name string `json:"name"`
    Tag  string `json:"tag,omitempty"`
}

Server (server.go)

Generates a server interface and registration function:

type ServerInterface interface {
    ListPets(ctx echo.Context) error
    CreatePet(ctx echo.Context) error
    GetPet(ctx echo.Context, id int64) error
}

func RegisterHandlers(e *echo.Echo, si ServerInterface) {
    // ...
}

Strict Server (strict_types.go, strict_server.go)

Type-safe server with parsed request/response objects:

type StrictServerInterface interface {
    GetPet(ctx context.Context, request GetPetRequest) (GetPetResponse, error)
}

type GetPetRequest struct {
    ID int64
}

type GetPetResponse interface {
    VisitGetPetResponse(w http.ResponseWriter) error
}

Client (client.go)

HTTP client with typed methods:

type Client struct {
    baseURL    string
    httpClient *http.Client
}

func (c *Client) GetPet(ctx context.Context, id int64) (*Pet, error) {
    // ...
}

Server Frameworks

Eugene supports three server frameworks:

Framework Flag Import
Echo echo github.com/labstack/echo/v4
Chi chi github.com/go-chi/chi/v5
stdlib stdlib net/http

OpenAPI Extensions

Eugene supports custom extensions for fine-grained control:

Extension Purpose Example
x-oink-go-type Override Go type x-oink-go-type: time.Duration
x-oink-go-type-import Import path x-oink-go-type-import: {path: "time"}
x-oink-go-name Override field/type name x-oink-go-name: CustomerID
x-oink-extra-tags Add struct tags x-oink-extra-tags: {validate: "required"}
x-oink-omitempty Force omitempty x-oink-omitempty: true
x-oink-omitzero Force omitzero x-oink-omitzero: true
x-oink-json-ignore Exclude from JSON x-oink-json-ignore: true

Example

components:
  schemas:
    User:
      type: object
      properties:
        id:
          type: string
          x-oink-go-type: uuid.UUID
          x-oink-go-type-import:
            path: github.com/google/uuid
        email:
          type: string
          x-oink-extra-tags:
            validate: required,email
            db: email

Enum Strategies

const (default)

type PetStatus string

const (
    PetStatusAvailable PetStatus = "available"
    PetStatusPending   PetStatus = "pending"
)

type

type PetStatus string

const (
    PetStatusAvailable PetStatus = "available"
    PetStatusPending   PetStatus = "pending"
)

struct

type PetStatus struct {
    value string
}

func (e PetStatus) String() string { return e.value }
func (e PetStatus) IsValid() bool { ... }

var (
    PetStatusAvailable = PetStatus{value: "available"}
    PetStatusPending   = PetStatus{value: "pending"}
)

AllOf Strategies

embed (default)

Uses Go struct embedding for allOf compositions when all components are references:

type Employee struct {
    Person     // embedded
    EmployeeID string `json:"employee_id"`
}

flatten

Merges all properties from allOf schemas into a single flat struct:

type Employee struct {
    Name       string `json:"name"`        // from Person
    Email      string `json:"email"`       // from Person
    EmployeeID string `json:"employee_id"`
}

Union Types (oneOf/anyOf)

Eugene generates union types with discriminator support:

type PaymentSource struct {
    Type string          `json:"-"`
    Raw  json.RawMessage `json:"-"`
}

func (s *PaymentSource) AsCard() (*Card, error) { ... }
func (s *PaymentSource) AsBankAccount() (*BankAccount, error) { ... }

A $ref variant's accessor is named after the schema. An inline variant's accessor is named after its Go type: string gives AsString(), []string gives AsStringList(), map[string]int gives AsIntMap() and time.Time gives AsTime(). An inline object generates a type and uses its name, such as AsPaymentSourceVariant(). Inline variants with the same Go type share one accessor, so string and format: date together give a single AsString(). If an inline variant's name clashes with a different type in the union, the inline one takes a numeric suffix (AsString2()) and generation prints a warning.

Set x-oink-go-name on an inline variant to choose its accessor name. It also keeps the name stable if variants are reordered, and two variants can use it to keep separate accessors for the same Go type. Using a name already taken in the union is a generation error.

Schedule:
  oneOf:
    - $ref: "#/components/schemas/Time"     # AsTime()
    - type: string
      format: date-time
      x-oink-go-name: StartsAt              # AsStartsAt() returns *time.Time

SSE/Streaming Support

Both client and server support Server-Sent Events:

Client:

stream, err := client.StreamEvents(ctx)
defer stream.Close()

for stream.Next() {
    event := stream.Current()
    var data MyEvent
    event.Decode(&data)
}

Server:

func (s *Server) StreamEvents(w http.ResponseWriter, r *http.Request) {
    sse, _ := NewSSEWriter(w)
    sse.WriteEvent("message", myData)
}

Custom Templates

Override built-in templates by providing a custom templates directory:

templates:
  dir: ./my-templates

Templates use Go's text/template with custom functions:

  • pascalCase, camelCase, snakeCase - naming conventions
  • goType - OpenAPI schema to Go type
  • goComment - format as Go comment
  • isRequired, isNullable - schema helpers

Project Structure

eugene/
β”œβ”€β”€ cmd/main.go           # CLI entry point
β”œβ”€β”€ internal/
β”‚   β”œβ”€β”€ cli/              # Cobra commands
β”‚   β”œβ”€β”€ config/           # Configuration
β”‚   β”œβ”€β”€ loader/           # OpenAPI parsing (libopenapi)
β”‚   β”œβ”€β”€ model/            # Internal representation
β”‚   β”œβ”€β”€ codegen/          # Generation pipeline
β”‚   β”œβ”€β”€ golang/           # Go-specific logic
β”‚   β”œβ”€β”€ templates/        # Template engine
β”‚   └── targets/          # Generation targets
β”œβ”€β”€ templates/            # Embedded templates
└── testdata/             # Test fixtures

Dependencies

Purpose Library
OpenAPI Parsing pb33f/libopenapi
CLI spf13/cobra
Config knadh/koanf
Formatting golang.org/x/tools/imports

Testing

Integration tests live in a separate tests/ module to avoid polluting the main module with framework-specific dependencies (Echo, Chi).

cd tests
go test ./...

License

MIT

About

Eugene - OpenAPI INterface Kit 🐷

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages