•  


GitHub - ogen-go/ogen: OpenAPI v3 code generator for go
Skip to content

ogen-go/ogen

Repository files navigation

ogen svg logo

ogen Go Reference codecov stable

OpenAPI v3 Code Generator for Go.

Install

go get -d github.com/ogen-go/ogen

Usage

//go:generate go run github.com/ogen-go/ogen/cmd/ogen --target target/dir -package api --clean schema.json

or using container:

docker run --rm \
  --volume 
"
.:/workspace
"
 \
  ghcr.io/ogen-go/ogen:latest --target workspace/petstore --clean workspace/petstore.yml

Features

  • No reflection or interface{}
    • The json encoding is code-generated, optimized and uses go-faster/jx for speed and overcoming encoding/json limitations
    • Validation is code-generated according to spec
  • Code-generated static radix router
  • No more boilerplate
    • Structures are generated from OpenAPI v3 specification
    • Arguments, headers, url queries are parsed according to specification into structures
    • String formats like uuid , date , date-time , uri are represented by go types directly
  • Statically typed client and server
  • Convenient support for optional, nullable and optional nullable fields
    • No more pointers
    • Generated Optional[T], Nullable[T] or OptionalNullable[T] wrappers with helpers
    • Special case for array handling with nil semantics relevant to specification
      • When array is optional, nil denotes absence of value
      • When nullable, nil denotes that value is nil
      • When required, nil currently the same as [] , but is actually invalid
      • If both nullable and required, wrapper will be generated (TODO)
  • Generated sum types for oneOf
    • Primitive types ( string , number ) are detected by type
    • Discriminator field is used if defined in schema
    • Type is inferred by unique fields if possible
  • Extra Go struct field tags in the generated types
  • OpenTelemetry tracing and metrics

Example generated structure from schema:

// Pet describes #/components/schemas/Pet.

type
 Pet
 struct
 {
	
Birthday
     time.
Time
     `json:"birthday"`

	Friends
      []
Pet
         `json:"friends"`

	ID
           int64
         `json:"id"`

	IP
           net.
IP
        `json:"ip"`

	IPV4
         net.
IP
        `json:"ip_v4"`

	IPV6
         net.
IP
        `json:"ip_v6"`

	Kind
         PetKind
       `json:"kind"`

	Name
         string
        `json:"name"`

	Next
         OptData
       `json:"next"`

	Nickname
     NilString
     `json:"nickname"`

	NullStr
      OptNilString
  `json:"nullStr"`

	Rate
         time.
Duration
 `json:"rate"`

	Tag
          OptUUID
       `json:"tag"`

	TestArray1
   [][]
string
    `json:"testArray1"`

	TestDate
     OptTime
       `json:"testDate"`

	TestDateTime
 OptTime
       `json:"testDateTime"`

	TestDuration
 OptDuration
   `json:"testDuration"`

	TestFloat1
   OptFloat64
    `json:"testFloat1"`

	TestInteger1
 OptInt
        `json:"testInteger1"`

	TestTime
     OptTime
       `json:"testTime"`

	Type
         OptPetType
    `json:"type"`

	URI
          url.
URL
       `json:"uri"`

	UniqueID
     uuid.
UUID
     `json:"unique_id"`

}

Example generated server interface:

// Server handles operations described by OpenAPI v3 specification.

type
 Server
 interface
 {
	
PetGetByName
(
ctx
 context.
Context
, 
params
 PetGetByNameParams
) (
Pet
, 
error
)
	
// ...

}

Example generated client method signature:

type
 PetGetByNameParams
 struct
 {
    
Name
 string

}

// GET /pet/{name}

func
 (
c
 *
Client
) 
PetGetByName
(
ctx
 context.
Context
, 
params
 PetGetByNameParams
) (
res
 Pet
, 
err
 error
)

Generics

Instead of using pointers, ogen generates generic wrappers.

For example, OptNilString is string that is optional (no value) and can be null .

// OptNilString is optional nullable string.

type
 OptNilString
 struct
 {
	
Value
 string

	Set
   bool

	Null
  bool

}

Multiple convenience helper methods and functions are generated, some of them:

func
 (
OptNilString
) 
Get
() (
v
 string
, 
ok
 bool
)
func
 (
OptNilString
) 
IsNull
() 
bool

func
 (
OptNilString
) 
IsSet
() 
bool


func
 NewOptNilString
(
v
 string
) 
OptNilString

Recursive types

If ogen encounters recursive types that can't be expressed in go, pointers are used as fallback.

Sum types

For oneOf sum-types are generated. ID that is one of [string, integer] will be represented like that:

type
 ID
 struct
 {
	
Type
   IDType

	String
 string

	Int
    int

}

// Also, some helpers:

func
 NewStringID
(
v
 string
) 
ID

func
 NewIntID
(
v
 int
) 
ID

Extension properties

OpenAPI enables Specification Extensions , which are implemented as patterned fields that are always prefixed by x- .

Server name

Optionally, server name can be specified by x-ogen-server-name , for example:

{
  
"openapi"
: 
"
3.0.3
"
,
  
"servers"
: [
    {
      
"x-ogen-server-name"
: 
"
production
"
,
      
"url"
: 
"
https://{region}.example.com/{val}/v1
"
,
    },
    {
      
"x-ogen-server-name"
: 
"
prefix
"
,
      
"url"
: 
"
/{val}/v1
"
,
    },
    {
      
"x-ogen-server-name"
: 
"
const
"
,
      
"url"
: 
"
https://cdn.example.com/v1
"

    }
  ],
(...)

Custom type name

Optionally, type name can be specified by x-ogen-name , for example:

{
  
"$schema"
: 
"
http://json-schema.org/draft-04/schema#
"
,
  
"type"
: 
"
object
"
,
  
"x-ogen-name"
: 
"
Name
"
,
  
"properties"
: {
    
"foobar"
: {
      
"$ref"
: 
"
#/$defs/FooBar
"

    }
  },
  
"$defs"
: {
    
"FooBar"
: {
      
"x-ogen-name"
: 
"
FooBar
"
,
      
"type"
: 
"
object
"
,
      
"properties"
: {
        
"foo"
: {
          
"type"
: 
"
string
"

        }
      }
    }
  }
}

Custom field name

Optionally, type name can be specified by x-ogen-properties , for example:

components
:
  
schemas
:
    
Node
:
      
type
: 
object

      properties
:
        
parent
:
          
$ref
: 
"
#/components/schemas/Node
"

        child
:
          
$ref
: 
"
#/components/schemas/Node
"

      x-ogen-properties
:
        
parent
:
          
name
: 
"
Prev
"

        child
:
          
name
: 
"
Next
"

The generated source code looks like:

// Ref: #/components/schemas/Node

type
 Node
 struct
 {
    
Prev
 *
Node
 `json:"parent"`

    Next
 *
Node
 `json:"child"`

}

Extra struct field tags

Optionally, additional Go struct field tags can be specified by x-oapi-codegen-extra-tags , for example:

components
:
  
schemas
:
    
Pet
:
      
type
: 
object

      required
:
        - 
id

      properties
:
        
id
:
          
type
: 
integer

          format
: 
int64

          x-oapi-codegen-extra-tags
:
            
gorm
: 
primaryKey

            valid
: 
customIdValidator

The generated source code looks like:

// Ref: #/components/schemas/Pet

type
 Pet
 struct
 {
    
ID
   int64
     `gorm:"primaryKey" valid:"customNameValidator" json:"id"`

}

Streaming JSON encoding

By default, ogen loads the entire JSON body into memory before decoding it. Optionally, streaming JSON encoding can be enabled by x-ogen-json-streaming , for example:

requestBody
:
  
required
: 
true

  content
:
    
application/json
:
      
x-ogen-json-streaming
: 
true

      schema
:
        
type
: 
array

        items
:
          
type
: 
number

Operation groups

Optionally, operations can be grouped so a handler interface will be generated for each group of operations. This is useful for organizing operations for large APIs.

The group for operations on a path or individual operations can be specified by x-ogen-operation-group , for example:

paths
:
  
/images
:
    
x-ogen-operation-group
: 
Images

    get
:
      
operationId
: 
listImages

      ...

  /images/{imageID}
:
    
x-ogen-operation-group
: 
Images

    get
:
      
operationId
: 
getImageByID

      ...

  /users
:
    
x-ogen-operation-group
: 
Users

    get
:
      
operationId
: 
listUsers

      ...

The generated handler interfaces look like this:

// x-ogen-operation-group: Images

type
 ImagesHandler
 interface
 {
    
ListImages
(
ctx
 context.
Context
, 
req
 *
ListImagesRequest
) (
*
ListImagesResponse
, 
error
)
    
GetImageByID
(
ctx
 context.
Context
, 
req
 *
GetImagesByIDRequest
) (
*
GetImagesByIDResponse
, 
error
)
}

// x-ogen-operation-group: Users

type
 UsersHandler
 interface
 {
    
ListUsers
(
ctx
 context.
Context
, 
req
 *
ListUsersRequest
) (
*
ListUsersResponse
, 
error
)
}

type
 Handler
 interface
 {
    
ImagesHandler

    UsersHandler

    // All un-grouped operations will be on this interface

}

JSON

Code generation provides very efficient and flexible encoding and decoding of json:

// Decode decodes Error from json.

func
 (
s
 *
Error
) 
Decode
(
d
 *
jx.
Decoder
) 
error
 {
	
if
 s
 ==
 nil
 {
		
return
 errors
.
New
(
"invalid: unable to decode Error to nil"
)
	}
	
return
 d
.
ObjBytes
(
func
(
d
 *
jx.
Decoder
, 
k
 []
byte
) 
error
 {
		
switch
 string
(
k
) {
		
case
 "code"
:
			
if
 err
 :=
 func
() 
error
 {
				
v
, 
err
 :=
 d
.
Int64
()
				
s
.
Code
 =
 int64
(
v
)
				
if
 err
 !=
 nil
 {
					
return
 err

				}
				
return
 nil

			}(); 
err
 !=
 nil
 {
				
return
 errors
.
Wrap
(
err
, 
"decode field 
\"
code
\"
"
)
			}
		
case
 "message"
:
			
if
 err
 :=
 func
() 
error
 {
				
v
, 
err
 :=
 d
.
Str
()
				
s
.
Message
 =
 string
(
v
)
				
if
 err
 !=
 nil
 {
					
return
 err

				}
				
return
 nil

			}(); 
err
 !=
 nil
 {
				
return
 errors
.
Wrap
(
err
, 
"decode field 
\"
message
\"
"
)
			}
		
default
:
			
return
 d
.
Skip
()
		}
		
return
 nil

	})
}

Links

- "漢字路" 한글한자자동변환 서비스는 교육부 고전문헌국역지원사업의 지원으로 구축되었습니다.
- "漢字路" 한글한자자동변환 서비스는 전통문화연구회 "울산대학교한국어처리연구실 옥철영(IT융합전공)교수팀"에서 개발한 한글한자자동변환기를 바탕하여 지속적으로 공동 연구 개발하고 있는 서비스입니다.
- 현재 고유명사(인명, 지명등)을 비롯한 여러 변환오류가 있으며 이를 해결하고자 많은 연구 개발을 진행하고자 하고 있습니다. 이를 인지하시고 다른 곳에서 인용시 한자 변환 결과를 한번 더 검토하시고 사용해 주시기 바랍니다.
- 변환오류 및 건의,문의사항은 juntong@juntong.or.kr로 메일로 보내주시면 감사하겠습니다. .
Copyright ⓒ 2020 By '전통문화연구회(傳統文化硏究會)' All Rights reserved.
 한국   대만   중국   일본