{"id":13602215,"url":"https://github.com/ogen-go/ogen","last_synced_at":"2026-02-28T13:13:10.465Z","repository":{"id":36951953,"uuid":"372032505","full_name":"ogen-go/ogen","owner":"ogen-go","description":"OpenAPI v3 code generator for go","archived":false,"fork":false,"pushed_at":"2025-05-07T06:50:56.000Z","size":72374,"stargazers_count":1693,"open_issues_count":98,"forks_count":112,"subscribers_count":15,"default_branch":"main","last_synced_at":"2025-05-07T07:43:26.357Z","etag":null,"topics":["api","code-generator","codegen","go","golang","openapi","openapi-codegen","openapi-generator","openapi3","rest","rest-api","restful-api","swagger"],"latest_commit_sha":null,"homepage":"https://ogen.dev","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ogen-go.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-05-29T17:25:48.000Z","updated_at":"2025-05-07T06:50:58.000Z","dependencies_parsed_at":"2024-01-05T04:24:52.880Z","dependency_job_id":"736f496d-63d5-4680-a026-85e1ded064c7","html_url":"https://github.com/ogen-go/ogen","commit_stats":{"total_commits":3300,"total_committers":46,"mean_commits":71.73913043478261,"dds":0.5460606060606061,"last_synced_commit":"4182357878201caf52384c2acd887b44d02a3a1f"},"previous_names":["ernado/ogen"],"tags_count":150,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ogen-go%2Fogen","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ogen-go%2Fogen/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ogen-go%2Fogen/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ogen-go%2Fogen/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ogen-go","download_url":"https://codeload.github.com/ogen-go/ogen/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254020485,"owners_count":22000750,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","code-generator","codegen","go","golang","openapi","openapi-codegen","openapi-generator","openapi3","rest","rest-api","restful-api","swagger"],"created_at":"2024-08-01T18:01:16.682Z","updated_at":"2026-02-28T13:13:10.456Z","avatar_url":"https://github.com/ogen-go.png","language":"Go","readme":"\u003cp align=\"center\"\u003e\n\u003cimg width=\"256\" height=\"256\" src=\"_logo/logo.svg\" alt=\"ogen svg logo\"\u003e\n\u003c/p\u003e\n\n# ogen [![Go Reference](https://img.shields.io/badge/go-pkg-00ADD8)](https://pkg.go.dev/github.com/ogen-go/ogen#section-documentation) [![codecov](https://img.shields.io/codecov/c/github/ogen-go/ogen?label=cover)](https://codecov.io/gh/ogen-go/ogen) [![stable](https://img.shields.io/badge/-stable-brightgreen)](https://go-faster.org/docs/projects/status#stable)\n\nOpenAPI v3 Code Generator for Go.\n\n- [Getting started](https://ogen.dev/docs/intro)\n- [Sample project](https://github.com/ogen-go/example)\n- [Security policy](https://github.com/ogen-go/ogen/blob/-/SECURITY.md)\n- [Telegram group `@ogen_dev`](https://t.me/ogen_dev)\n\n# Install\n\n```console\ngo install -v github.com/ogen-go/ogen/cmd/ogen@latest\n```\n\n# Usage\n\n```go\n//go:generate go run github.com/ogen-go/ogen/cmd/ogen --target target/dir -package api --clean schema.json\n```\n\nor using container:\n```shell\ndocker run --rm \\\n  --volume \".:/workspace\" \\\n  ghcr.io/ogen-go/ogen:latest --target workspace/petstore --clean workspace/petstore.yml\n```\n\n# Features\n\n- No reflection or `interface{}`\n  - The json encoding is code-generated, optimized and uses [go-faster/jx](https://github.com/go-faster/jx) for speed and overcoming `encoding/json` limitations\n  - Validation is code-generated according to spec\n- Code-generated static radix router\n- No more boilerplate\n  - Structures are generated from OpenAPI v3 specification\n  - Arguments, headers, url queries are parsed according to specification into structures\n  - String formats like `uuid`, `date`, `date-time`, `uri` are represented by go types directly\n- Statically typed client and server\n- Convenient support for optional, nullable and optional nullable fields\n  - No more pointers\n  - Generated Optional[T], Nullable[T] or OptionalNullable[T] wrappers with helpers\n  - Special case for array handling with `nil` semantics relevant to specification\n    - When array is optional, `nil` denotes absence of value\n    - When nullable, `nil` denotes that value is `nil`\n    - When required, `nil` currently the same as `[]`, but is actually invalid\n    - If both nullable and required, wrapper will be generated (TODO)\n- Support for untyped parameters (any)\n  - Parameters with no `type` specified in schema are represented as Go `any`\n  - Decoded as strings from URI (path, query, header, cookie)\n  - Client encoding uses `fmt.Sprint` for flexible value conversion\n  - Useful for legacy APIs or dynamic parameter types\n- Generated sum types for oneOf\n  - Primitive types (`string`, `number`) are detected by type\n  - Discriminator field is used if defined in schema\n  - Type is inferred by unique fields if possible\n    - Field name discrimination: variants with different field names\n    - Field type discrimination: variants with same field names but different types (e.g., `{id: string}` vs `{id: integer}`)\n    - Field value discrimination: variants with same field names and types but different enum values\n- Extra Go struct field tags in the generated types\n- OpenTelemetry tracing and metrics\n\nExample generated structure from schema:\n\n```go\n// Pet describes #/components/schemas/Pet.\ntype Pet struct {\n\tBirthday     time.Time     `json:\"birthday\"`\n\tFriends      []Pet         `json:\"friends\"`\n\tID           int64         `json:\"id\"`\n\tIP           net.IP        `json:\"ip\"`\n\tIPV4         net.IP        `json:\"ip_v4\"`\n\tIPV6         net.IP        `json:\"ip_v6\"`\n\tKind         PetKind       `json:\"kind\"`\n\tName         string        `json:\"name\"`\n\tNext         OptData       `json:\"next\"`\n\tNickname     NilString     `json:\"nickname\"`\n\tNullStr      OptNilString  `json:\"nullStr\"`\n\tRate         time.Duration `json:\"rate\"`\n\tTag          OptUUID       `json:\"tag\"`\n\tTestArray1   [][]string    `json:\"testArray1\"`\n\tTestDate     OptTime       `json:\"testDate\"`\n\tTestDateTime OptTime       `json:\"testDateTime\"`\n\tTestDuration OptDuration   `json:\"testDuration\"`\n\tTestFloat1   OptFloat64    `json:\"testFloat1\"`\n\tTestInteger1 OptInt        `json:\"testInteger1\"`\n\tTestTime     OptTime       `json:\"testTime\"`\n\tType         OptPetType    `json:\"type\"`\n\tURI          url.URL       `json:\"uri\"`\n\tUniqueID     uuid.UUID     `json:\"unique_id\"`\n}\n```\n\nExample generated server interface:\n\n```go\n// Server handles operations described by OpenAPI v3 specification.\ntype Server interface {\n\tPetGetByName(ctx context.Context, params PetGetByNameParams) (Pet, error)\n\t// ...\n}\n```\n\nExample generated client method signature:\n\n```go\ntype PetGetByNameParams struct {\n    Name string\n}\n\n// GET /pet/{name}\nfunc (c *Client) PetGetByName(ctx context.Context, params PetGetByNameParams) (res Pet, err error)\n```\n\n## Generics\n\nInstead of using pointers, `ogen` generates generic wrappers.\n\nFor example, `OptNilString` is `string` that is optional (no value) and can be `null`.\n\n```go\n// OptNilString is optional nullable string.\ntype OptNilString struct {\n\tValue string\n\tSet   bool\n\tNull  bool\n}\n```\n\nMultiple convenience helper methods and functions are generated, some of them:\n\n```go\nfunc (OptNilString) Get() (v string, ok bool)\nfunc (OptNilString) IsNull() bool\nfunc (OptNilString) IsSet() bool\n\nfunc NewOptNilString(v string) OptNilString\n```\n\n## Recursive types\n\nIf `ogen` encounters recursive types that can't be expressed in go, pointers are used as fallback.\n\n## Sum types\n\nFor `oneOf` sum-types are generated. `ID` that is one of `[string, integer]` will be represented like that:\n\n```go\ntype ID struct {\n\tType   IDType\n\tString string\n\tInt    int\n}\n\n// Also, some helpers:\nfunc NewStringID(v string) ID\nfunc NewIntID(v int) ID\n```\n\n### Discriminator Inference\n\nogen automatically infers how to discriminate between oneOf variants using several strategies:\n\n**1. Type-based discrimination** (for primitive types)\n\nVariants with different JSON types are discriminated by checking the JSON type at runtime:\n\n```json\n{\n  \"oneOf\": [\n    {\"type\": \"string\"},\n    {\"type\": \"integer\"}\n  ]\n}\n```\n\n**2. Explicit discriminator** (when discriminator field is specified)\n\nWhen a discriminator field is defined in the schema, ogen uses it directly:\n\n```json\n{\n  \"oneOf\": [...],\n  \"discriminator\": {\n    \"propertyName\": \"type\",\n    \"mapping\": {\"user\": \"#/components/schemas/User\", ...}\n  }\n}\n```\n\n**3. Field-based discrimination** (automatic inference from unique fields)\n\nogen analyzes the fields in each variant to find discriminating characteristics:\n\n- **Field name discrimination**: Variants have different field names\n\n```json\n{\n  \"oneOf\": [\n    {\"type\": \"object\", \"required\": [\"userId\"], \"properties\": {\"userId\": {\"type\": \"string\"}}},\n    {\"type\": \"object\", \"required\": [\"orderId\"], \"properties\": {\"orderId\": {\"type\": \"string\"}}}\n  ]\n}\n```\n\n- **Field type discrimination**: Variants have fields with the same name but different types\n\n```json\n{\n  \"oneOf\": [\n    {\n      \"type\": \"object\",\n      \"required\": [\"id\", \"value\"],\n      \"properties\": {\n        \"id\": {\"type\": \"string\"},\n        \"value\": {\"type\": \"string\"}\n      }\n    },\n    {\n      \"type\": \"object\",\n      \"required\": [\"id\", \"value\"],\n      \"properties\": {\n        \"id\": {\"type\": \"integer\"},\n        \"value\": {\"type\": \"number\"}\n      }\n    }\n  ]\n}\n```\n\nIn this case, ogen checks the JSON type of the `id` field at runtime to determine which variant to decode.\n\n- **Field value discrimination**: Variants have fields with the same name and type but different enum values\n\n```json\n{\n  \"oneOf\": [\n    {\n      \"type\": \"object\",\n      \"required\": [\"status\"],\n      \"properties\": {\n        \"status\": {\"type\": \"string\", \"enum\": [\"active\", \"pending\"]}\n      }\n    },\n    {\n      \"type\": \"object\",\n      \"required\": [\"status\"],\n      \"properties\": {\n        \"status\": {\"type\": \"string\", \"enum\": [\"inactive\", \"deleted\"]}\n      }\n    }\n  ]\n}\n```\n\nIn this case, ogen checks the actual string value of the `status` field at runtime and matches it against each variant's enum values. The enum values must be disjoint (non-overlapping) for this to work. If enum values overlap, ogen will report an error and suggest using an explicit discriminator.\n\n## Const values\n\nogen supports the JSON Schema [`const`](https://json-schema.org/understanding-json-schema/reference/generic#constant-values) keyword, which specifies that a field must have a fixed value (introduced in [JSON Schema draft 6](https://json-schema.org/draft-06/json-schema-release-notes.html) and supported in OpenAPI 3.0+). When a field has a `const` value, it is encoded directly in the generated JSON encoder without requiring the struct field to be set.\n\n### Example schema with const values\n\n```yaml\ncomponents:\n  schemas:\n    ErrorResponse:\n      type: object\n      properties:\n        code:\n          type: integer\n          const: 400\n        status:\n          type: string\n          const: \"error\"\n        message:\n          type: string\n```\n\n### Generated code\n\nThe generated struct includes the field, but the encoder hardcodes the const value:\n\n```go\ntype ErrorResponse struct {\n    Code    int64  `json:\"code\"`    // const: 400\n    Status  string `json:\"status\"`  // const: \"error\"\n    Message string `json:\"message\"`\n}\n\nfunc (s *ErrorResponse) encodeFields(e *jx.Encoder) {\n    {\n        e.FieldStart(\"code\")\n        e.Int64(400)  // Const value encoded directly\n    }\n    {\n        e.FieldStart(\"status\")\n        e.Str(\"error\")  // Const value encoded directly\n    }\n    {\n        e.FieldStart(\"message\")\n        e.Str(s.Message)  // Regular field\n    }\n}\n```\n\n### Benefits\n\n- **Simplified initialization**: You don't need to set const fields when creating struct instances\n- **Type safety**: Const values are validated at code generation time\n- **Performance**: Const values are encoded directly without runtime lookups\n- **Works with allOf**: Const values are preserved when merging schemas with `allOf`\n\n### Supported const value types\n\n- Primitives: `integer`, `number`, `string`, `boolean`\n- Special values: `null`, empty strings (`\"\"`), zero values (`0`, `false`)\n- Complex types: `object`, `array` (when specified in schema)\n\n## Extension properties\n\nOpenAPI enables [Specification Extensions](https://spec.openapis.org/oas/v3.1.0#specification-extensions),\nwhich are implemented as patterned fields that are always prefixed by `x-`.\n\n### Server name\n\nOptionally, server name can be specified by `x-ogen-server-name`, for example:\n\n```json\n{\n  \"openapi\": \"3.0.3\",\n  \"servers\": [\n    {\n      \"x-ogen-server-name\": \"production\",\n      \"url\": \"https://{region}.example.com/{val}/v1\",\n    },\n    {\n      \"x-ogen-server-name\": \"prefix\",\n      \"url\": \"/{val}/v1\",\n    },\n    {\n      \"x-ogen-server-name\": \"const\",\n      \"url\": \"https://cdn.example.com/v1\"\n    }\n  ],\n(...)\n```\n\n### Custom type name\n\nOptionally, type name can be specified by `x-ogen-name`, for example:\n\n```json\n{\n  \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n  \"type\": \"object\",\n  \"x-ogen-name\": \"Name\",\n  \"properties\": {\n    \"foobar\": {\n      \"$ref\": \"#/$defs/FooBar\"\n    }\n  },\n  \"$defs\": {\n    \"FooBar\": {\n      \"x-ogen-name\": \"FooBar\",\n      \"type\": \"object\",\n      \"properties\": {\n        \"foo\": {\n          \"type\": \"string\"\n        }\n      }\n    }\n  }\n}\n```\n\n### Custom field name\n\nOptionally, type name can be specified by `x-ogen-properties`, for example:\n\n```yaml\ncomponents:\n  schemas:\n    Node:\n      type: object\n      properties:\n        parent:\n          $ref: \"#/components/schemas/Node\"\n        child:\n          $ref: \"#/components/schemas/Node\"\n      x-ogen-properties:\n        parent:\n          name: \"Prev\"\n        child:\n          name: \"Next\"\n```\n\nThe generated source code looks like:\n\n```go\n// Ref: #/components/schemas/Node\ntype Node struct {\n    Prev *Node `json:\"parent\"`\n    Next *Node `json:\"child\"`\n}\n```\n\n### Extra struct field tags\n\nOptionally, additional Go struct field tags can be specified by `x-oapi-codegen-extra-tags`, for example:\n\n```yaml\ncomponents:\n  schemas:\n    Pet:\n      type: object\n      required:\n        - id\n      properties:\n        id:\n          type: integer\n          format: int64\n          x-oapi-codegen-extra-tags:\n            gorm: primaryKey\n            valid: customIdValidator\n```\n\nThe generated source code looks like:\n\n```go\n// Ref: #/components/schemas/Pet\ntype Pet struct {\n    ID   int64     `gorm:\"primaryKey\" valid:\"customNameValidator\" json:\"id\"`\n}\n```\n\n### Streaming JSON encoding\n\nBy default, ogen loads the entire JSON body into memory before decoding it.\nOptionally, streaming JSON encoding can be enabled by `x-ogen-json-streaming`, for example:\n\n```yaml\nrequestBody:\n  required: true\n  content:\n    application/json:\n      x-ogen-json-streaming: true\n      schema:\n        type: array\n        items:\n          type: number\n```\n\n### Custom validation\n\nOptionally, custom validation can be specified by `x-ogen-validate`, for example:\n\n```yaml\ncomponents:\n  schemas:\n    Product:\n      type: object\n      properties:\n        name:\n          type: string\n          x-ogen-validate:\n            minWords: 2\n        tags:\n          type: array\n          items:\n            type: string\n          x-ogen-validate:\n            uniqueItems: true\n        metadata:\n          type: object\n          additionalProperties: true\n          x-ogen-validate:\n            fieldCount:\n              min: 1\n              max: 10\n```\n\nCustom validators must be registered before validation is performed:\n\n```go\nimport \"github.com/ogen-go/ogen/validate\"\n\n// Register validators\nvalidate.RegisterValidator(\"minWords\", func(value any, params any) error {\n    // ... validate minimum word count\n})\n\nvalidate.RegisterValidator(\"uniqueItems\", func(value any, params any) error {\n    // ... validate array has no duplicate items\n})\n\nvalidate.RegisterValidator(\"fieldCount\", func(value any, params any) error {\n    // ... validate object field count within min/max range\n})\n```\n\n### Operation groups\n\nOptionally, operations can be grouped so a handler interface will be generated for each group of operations.\nThis is useful for organizing operations for large APIs.\n\nThe group for operations on a path or individual operations can be specified by `x-ogen-operation-group`, for example:\n\n```yaml\npaths:\n  /images:\n    x-ogen-operation-group: Images\n    get:\n      operationId: listImages\n      ...\n  /images/{imageID}:\n    x-ogen-operation-group: Images\n    get:\n      operationId: getImageByID\n      ...\n  /users:\n    x-ogen-operation-group: Users\n    get:\n      operationId: listUsers\n      ...\n```\n\nThe generated handler interfaces look like this:\n\n```go\n// x-ogen-operation-group: Images\ntype ImagesHandler interface {\n    ListImages(ctx context.Context, req *ListImagesRequest) (*ListImagesResponse, error)\n    GetImageByID(ctx context.Context, req *GetImagesByIDRequest) (*GetImagesByIDResponse, error)\n}\n\n// x-ogen-operation-group: Users\ntype UsersHandler interface {\n    ListUsers(ctx context.Context, req *ListUsersRequest) (*ListUsersResponse, error)\n}\n\ntype Handler interface {\n    ImagesHandler\n    UsersHandler\n    // All un-grouped operations will be on this interface\n}\n```\n\n## JSON\n\nCode generation provides very efficient and flexible encoding and decoding of json:\n\n```go\n// Decode decodes Error from json.\nfunc (s *Error) Decode(d *jx.Decoder) error {\n\tif s == nil {\n\t\treturn errors.New(\"invalid: unable to decode Error to nil\")\n\t}\n\treturn d.ObjBytes(func(d *jx.Decoder, k []byte) error {\n\t\tswitch string(k) {\n\t\tcase \"code\":\n\t\t\tif err := func() error {\n\t\t\t\tv, err := d.Int64()\n\t\t\t\ts.Code = int64(v)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t}(); err != nil {\n\t\t\t\treturn errors.Wrap(err, \"decode field \\\"code\\\"\")\n\t\t\t}\n\t\tcase \"message\":\n\t\t\tif err := func() error {\n\t\t\t\tv, err := d.Str()\n\t\t\t\ts.Message = string(v)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t}(); err != nil {\n\t\t\t\treturn errors.Wrap(err, \"decode field \\\"message\\\"\")\n\t\t\t}\n\t\tdefault:\n\t\t\treturn d.Skip()\n\t\t}\n\t\treturn nil\n\t})\n}\n```\n\n# Links\n\n- [Getting started](https://ogen.dev/docs/intro)\n- [Sample project](https://github.com/ogen-go/example)\n- [Security policy](https://github.com/ogen-go/ogen/blob/-/SECURITY.md)\n- [Telegram chat `@ogen_dev`](https://t.me/ogen_dev)\n","funding_links":[],"categories":["API tools","Go","api"],"sub_categories":["Threat modelling"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fogen-go%2Fogen","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fogen-go%2Fogen","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fogen-go%2Fogen/lists"}