Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
e778d93
Feat: Codegen v3 experiment
deepmap-marcinr Feb 4, 2026
63de366
Add support for external references
deepmap-marcinr Feb 4, 2026
a06eab4
Parameterize content types for models
deepmap-marcinr Feb 4, 2026
38684e9
Parameterize struct tags
deepmap-marcinr Feb 4, 2026
6789565
Skip automated tests for now.
deepmap-marcinr Feb 4, 2026
3b8795b
Update generated code, fix CI
mromaszewicz Feb 4, 2026
9fc5e8a
Clean up allOf schema naming
mromaszewicz Feb 4, 2026
efd49d1
Clean up naming in path schemas
mromaszewicz Feb 4, 2026
276baf8
Verify currently open schema gen issues
mromaszewicz Feb 4, 2026
5ec10d4
Ensure old bugs don't regress
mromaszewicz Feb 5, 2026
c841955
Handle Nullable as before
mromaszewicz Feb 5, 2026
622cd2e
Extension property support
mromaszewicz Feb 5, 2026
22503f7
Fix linter errors
mromaszewicz Feb 5, 2026
99951b6
Add parameter styling and binding
mromaszewicz Feb 5, 2026
8807e5c
Implement http.ServeMux server
mromaszewicz Feb 5, 2026
8ba1f56
Update to more recent libopenapi
mromaszewicz Feb 5, 2026
3e31447
Add client generation support
mromaszewicz Feb 5, 2026
6700435
Hook up client generation to command line
mromaszewicz Feb 5, 2026
ecffa41
Support models being external
mromaszewicz Feb 5, 2026
efe250e
Add all supported routers
mromaszewicz Feb 6, 2026
3881254
Add Echo V5 support
mromaszewicz Feb 6, 2026
d144036
Embed the OpenAPI spec in generated code for
mromaszewicz Feb 6, 2026
19a245a
Fix lint issues
mromaszewicz Feb 6, 2026
dac2d8e
Update libopenapi, external ref changes
mromaszewicz Feb 6, 2026
676a7f1
Support webhooks and callbacks
mromaszewicz Feb 6, 2026
8222c4b
Remove the concept of stable names
mromaszewicz Feb 6, 2026
679e956
Fix lint errors due to Go versioning
mromaszewicz Feb 6, 2026
3b0aded
Update READMEs and fix lint issue
mromaszewicz Feb 7, 2026
2066ed8
Fix nondeterministic map order issue
mromaszewicz Feb 7, 2026
44eed56
Fix Markdown formatting issue
mromaszewicz Feb 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,34 +19,34 @@ lint: tools
# run the root module explicitly, to prevent recursive calls by re-invoking `make ...` top-level
$(GOBIN)/golangci-lint run ./...
# then, for all child modules, use a module-managed `Makefile`
git ls-files '**/*go.mod' -z | xargs -0 -I{} bash -xc 'cd $$(dirname {}) && env GOBIN=$(GOBIN) make lint'
GOBIN=$(GOBIN) ./scripts/foreach-module.sh lint

lint-ci: tools
# for the root module, explicitly run the step, to prevent recursive calls
$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m
# then, for all child modules, use a module-managed `Makefile`
git ls-files '**/*go.mod' -z | xargs -0 -I{} bash -xc 'cd $$(dirname {}) && env GOBIN=$(GOBIN) make lint-ci'
GOBIN=$(GOBIN) ./scripts/foreach-module.sh lint-ci

generate:
# for the root module, explicitly run the step, to prevent recursive calls
go generate ./...
# then, for all child modules, use a module-managed `Makefile`
git ls-files '**/*go.mod' -z | xargs -0 -I{} bash -xc 'cd $$(dirname {}) && make generate'
GOBIN=$(GOBIN) ./scripts/foreach-module.sh generate

test:
# for the root module, explicitly run the step, to prevent recursive calls
go test -cover ./...
# then, for all child modules, use a module-managed `Makefile`
git ls-files '**/*go.mod' -z | xargs -0 -I{} bash -xc 'cd $$(dirname {}) && make test'
GOBIN=$(GOBIN) ./scripts/foreach-module.sh test

tidy:
# for the root module, explicitly run the step, to prevent recursive calls
go mod tidy
# then, for all child modules, use a module-managed `Makefile`
git ls-files '**/*go.mod' -z | xargs -0 -I{} bash -xc 'cd $$(dirname {}) && make tidy'
GOBIN=$(GOBIN) ./scripts/foreach-module.sh tidy

tidy-ci:
# for the root module, explicitly run the step, to prevent recursive calls
tidied -verbose
# then, for all child modules, use a module-managed `Makefile`
git ls-files '**/*go.mod' -z | xargs -0 -I{} bash -xc 'cd $$(dirname {}) && make tidy-ci'
GOBIN=$(GOBIN) ./scripts/foreach-module.sh tidy-ci
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,9 @@ We can see that this provides the best means to focus on the implementation of t
- Single-file output
- Support multiple OpenAPI files by having a package-per-OpenAPI file
- Support of OpenAPI 3.0
- OpenAPI 3.1 support is [awaiting upstream support](https://github.com/oapi-codegen/oapi-codegen/issues/373)
- OpenAPI 3.1 support is in experimental form, as a complete rewrite using [libopenapi](https://github.com/pb33f/libopenapi). Please look in the
`./experimental` directory. This is potentially the future V3 of `oapi-codegen` and is functionally complete, just not deeply tested yet. Many OpenAPI 3.1
features are supported, such as webhooks and callbacks.
- Note that this does not include OpenAPI 2.0 (aka Swagger)
- Extract parameters from requests, to reduce work required by your implementation
- Implicit `additionalProperties` are ignored by default ([more details](#additional-properties-additionalproperties))
Expand Down
246 changes: 246 additions & 0 deletions experimental/Configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
# Configuration Reference

`oapi-codegen` is configured using a YAML file. All sections are optional — you only need to include what you want to change from the defaults.

Below is a fully annotated configuration file showing every option.

```yaml
# The Go package name for generated code.
# Can also be set with -package flag.
package: myapi

# Output file path.
# Can also be set with -output flag.
# Default: <spec-basename>.gen.go
output: types.gen.go

# Generation controls which parts of the code are generated.
generation:
# Server framework to generate code for.
# Supported: "std-http", "chi", "echo", "echo/v4", "gin", "gorilla", "fiber", "iris"
# Default: "" (no server code generated)
server: std-http

# Generate an HTTP client that returns *http.Response.
# Default: false
client: true

# Generate a SimpleClient wrapper with typed responses.
# Requires client: true.
# Default: false
simple-client: true

# Use model types from an external package instead of generating them locally.
# When set, models are imported rather than generated.
# Default: not set (models are generated locally)
models-package:
path: github.com/org/project/models
alias: models # optional, defaults to last segment of path

# Type mappings: OpenAPI type/format to Go type.
# User values are merged on top of defaults — you only need to specify overrides.
type-mapping:
integer:
default:
type: int # default
formats:
int32:
type: int32 # default
int64:
type: int64 # default
number:
default:
type: float32 # default
formats:
double:
type: float64 # default
boolean:
default:
type: bool # default
string:
default:
type: string # default
formats:
byte:
type: "[]byte" # default
date:
type: Date # default, custom template type
date-time:
type: time.Time # default
import: time
uuid:
type: UUID # default, custom template type
email:
type: Email # default, custom template type
binary:
type: File # default, custom template type
json:
type: json.RawMessage # default
import: encoding/json
# Add your own format mappings:
money:
type: decimal.Decimal
import: github.com/shopspring/decimal

# Name mangling: controls how OpenAPI names become Go identifiers.
# User values are merged on top of defaults.
name-mangling:
# Prefix prepended when a name starts with a digit.
# Default: "N" (e.g., "123foo" becomes "N123foo")
numeric-prefix: "N"

# Prefix prepended when a name conflicts with a Go keyword.
# Default: "" (uses keyword-suffix instead)
keyword-prefix: ""

# Characters that mark word boundaries (next letter is capitalised).
# Default includes most punctuation: - # @ ! $ & = . + : ; _ ~ space ( ) { } [ ] | < > ? / \
word-separators: "-#@!$&=.+:;_~ (){}[]|<>?/\\"

# Words that should remain all-uppercase.
initialisms:
- ACL
- API
- ASCII
- CPU
- CSS
- DB
- DNS
- EOF
- GUID
- HTML
- HTTP
- HTTPS
- ID
- IP
- JSON
- QPS
- RAM
- RPC
- SLA
- SMTP
- SQL
- SSH
- TCP
- TLS
- TTL
- UDP
- UI
- UID
- GID
- URI
- URL
- UTF8
- UUID
- VM
- XML
- XMPP
- XSRF
- XSS
- SIP
- RTP
- AMQP
- TS

# Characters that get replaced with words when they appear at the start of a name.
character-substitutions:
"$": DollarSign
"-": Minus
"+": Plus
"&": And
"|": Or
"~": Tilde
"=": Equal
">": GreaterThan
"<": LessThan
"#": Hash
".": Dot
"*": Asterisk
"^": Caret
"%": Percent
"_": Underscore
"@": At
"!": Bang
"?": Question
"/": Slash
"\\": Backslash
":": Colon
";": Semicolon
"'": Apos
"\"": Quote
"`": Backtick
"(": LParen
")": RParen
"[": LBracket
"]": RBracket
"{": LBrace
"}": RBrace

# Name substitutions: direct overrides for specific generated names.
name-substitutions:
# Override type names during generation.
type-names:
foo: MyCustomFoo # Schema "foo" generates type "MyCustomFoo" instead of "Foo"
# Override property/field names during generation.
property-names:
bar: MyCustomBar # Property "bar" generates field "MyCustomBar" instead of "Bar"

# Import mapping: resolve external $ref targets to Go packages.
# Required when your spec references schemas from other files.
import-mapping:
../common/api.yaml: github.com/org/project/common
https://example.com/specs/shared.yaml: github.com/org/shared
# Use "-" to indicate types should stay in the current package
./local-types.yaml: "-"

# Content types: regexp patterns controlling which media types generate models.
# Only request/response bodies with matching content types will have types generated.
# Default: JSON types only.
content-types:
- "^application/json$"
- "^application/.*\\+json$"
# Add custom patterns as needed:
# - "^application/xml$"
# - "^text/plain$"

# Content type short names: maps content type patterns to short names
# used in generated type names (e.g., "FindPetsJSONResponse").
content-type-short-names:
- pattern: "^application/json$"
short-name: JSON
- pattern: "^application/xml$"
short-name: XML
- pattern: "^text/plain$"
short-name: Text
# ... defaults cover JSON, XML, Text, HTML, Binary, Multipart, Form

# Struct tags: controls which struct tags are generated and their format.
# Uses Go text/template syntax. If specified, completely replaces the defaults.
# Default: json and form tags.
struct-tags:
tags:
- name: json
template: '{{if .JSONIgnore}}-{{else}}{{ .FieldName }}{{if .OmitEmpty}},omitempty{{end}}{{if .OmitZero}},omitzero{{end}}{{end}}'
- name: form
template: '{{if .JSONIgnore}}-{{else}}{{ .FieldName }}{{if .OmitEmpty}},omitempty{{end}}{{end}}'
# Add additional tags:
- name: yaml
template: '{{ .FieldName }}{{if .OmitEmpty}},omitempty{{end}}'
- name: db
template: '{{ .FieldName }}'
```

## Struct tag template variables

The struct tag templates have access to the following fields:

| Variable | Type | Description |
|----------|------|-------------|
| `.FieldName` | `string` | The original field name from the OpenAPI spec |
| `.GoFieldName` | `string` | The Go identifier name after name mangling |
| `.IsOptional` | `bool` | Whether the field is optional in the schema |
| `.IsNullable` | `bool` | Whether the field is nullable |
| `.IsPointer` | `bool` | Whether the field is rendered as a pointer type |
| `.OmitEmpty` | `bool` | Whether `omitempty` should be applied (from extensions or optionality) |
| `.OmitZero` | `bool` | Whether `omitzero` should be applied (from `x-oapi-codegen-omitzero` extension) |
| `.JSONIgnore` | `bool` | Whether the field should be ignored in JSON (from `x-go-json-ignore` extension) |
35 changes: 35 additions & 0 deletions experimental/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
SHELL:=/bin/bash

YELLOW := \e[0;33m
RESET := \e[0;0m

GOVER := $(shell go env GOVERSION)
GOMINOR := $(shell bash -c "cut -f1 -d' ' <<< \"$(GOVER)\" | cut -f2 -d.")

define execute-if-go-124
@{ \
if [[ 24 -le $(GOMINOR) ]]; then \
$1; \
else \
echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.24, which this module requires$(RESET)"; \
fi \
}
endef

lint:
$(call execute-if-go-124,$(GOBIN)/golangci-lint run ./...)

lint-ci:
$(call execute-if-go-124,$(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m)

generate:
$(call execute-if-go-124,go generate ./...)

test:
@echo "Skipping tests in experimental module"

tidy:
$(call execute-if-go-124,go mod tidy)

tidy-ci:
$(call execute-if-go-124,tidied -verbose)
Loading