openapi
API
openapi
packageAPI reference for the openapi
package.
Imports
(4)
S
struct
Document
Document represents an OpenAPI 3.0.3 document.
pkg/openapi/openapi.go:10-14
type Document struct
Fields
| Name | Type | Description |
|---|---|---|
| OpenAPI | string | json:"openapi" |
| Info | Info | json:"info" |
| Paths | map[string]PathItem | json:"paths" |
Uses
S
struct
Info
Info holds the API title and version.
pkg/openapi/openapi.go:17-20
type Info struct
Fields
| Name | Type | Description |
|---|---|---|
| Title | string | json:"title" |
| Version | string | json:"version" |
T
type
PathItem
PathItem maps HTTP methods to operations for a path.
pkg/openapi/openapi.go:23-23
type PathItem map[string]Operation
S
struct
Operation
Operation describes a single API operation.
pkg/openapi/openapi.go:26-31
type Operation struct
Fields
| Name | Type | Description |
|---|---|---|
| Summary | string | json:"summary,omitempty" |
| Description | string | json:"description,omitempty" |
| Parameters | []Parameter | json:"parameters,omitempty" |
| Responses | map[string]Response | json:"responses" |
S
struct
Parameter
Parameter describes an operation parameter.
pkg/openapi/openapi.go:34-39
type Parameter struct
Fields
| Name | Type | Description |
|---|---|---|
| Name | string | json:"name" |
| In | string | json:"in" |
| Required | bool | json:"required" |
| Schema | Schema | json:"schema" |
Uses
S
struct
Schema
Schema describes a parameter schema.
pkg/openapi/openapi.go:42-46
type Schema struct
Fields
| Name | Type | Description |
|---|---|---|
| Type | string | json:"type,omitempty" |
| Minimum | *float64 | json:"minimum,omitempty" |
| Enum | []string | json:"enum,omitempty" |
S
struct
Response
Response describes an operation response.
pkg/openapi/openapi.go:49-51
type Response struct
Fields
| Name | Type | Description |
|---|---|---|
| Description | string | json:"description" |
I
interface
MetaProvider
MetaProvider is an optional interface endpoints can implement for OpenAPI metadata.
pkg/openapi/openapi.go:54-56
type MetaProvider interface
Methods
F
function
Build
Build generates an OpenAPI 3.0.3 JSON document from struct-tagged handlers.
Each handler must have method and path struct tags.
Parameters
title
string
version
string
handlers
...any
Returns
[]byte
error
pkg/openapi/openapi.go:60-131
func Build(title, version string, handlers ...any) ([]byte, error)
{
doc := Document{
OpenAPI: "3.0.3",
Info: Info{
Title: title,
Version: version,
},
Paths: map[string]PathItem{},
}
for _, h := range handlers {
val := reflect.ValueOf(h)
if val.Kind() == reflect.Ptr {
val = val.Elem()
}
typ := val.Type()
var method, path string
extractTags(typ, &method, &path)
if method == "" || path == "" {
continue
}
op := Operation{
Responses: map[string]Response{"200": {Description: "OK"}},
}
discoverParameters(typ, &op)
if mp, ok := h.(MetaProvider); ok {
m := mp.OpenAPIMeta()
if s, ok := m["summary"].(string); ok {
op.Summary = s
}
if d, ok := m["description"].(string); ok {
op.Description = d
}
if params, ok := m["parameters"].([]map[string]any); ok {
for _, pm := range params {
p := Parameter{Name: pm["name"].(string), In: pm["in"].(string)}
if req, ok := pm["required"].(bool); ok {
p.Required = req
}
if sch, ok := pm["schema"].(map[string]any); ok {
p.Schema.Type, _ = sch["type"].(string)
if min, ok := sch["minimum"].(int); ok {
f := float64(min)
p.Schema.Minimum = &f
}
}
op.Parameters = append(op.Parameters, p)
}
}
if resp, ok := m["responses"].(map[int]any); ok {
op.Responses = map[string]Response{}
for code, desc := range resp {
op.Responses[codeToStr(code)] = Response{Description: desc.(string)}
}
}
}
pathItem, ok := doc.Paths[path]
if !ok {
pathItem = make(PathItem)
}
pathItem[method] = op
doc.Paths[path] = pathItem
}
return json.MarshalIndent(doc, "", " ")
}
F
function
goTypeToOpenAPI
Parameters
Returns
string
pkg/openapi/openapi.go:133-146
func goTypeToOpenAPI(t reflect.Type) string
{
switch t.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return "integer"
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return "integer"
case reflect.Float32, reflect.Float64:
return "number"
case reflect.Bool:
return "boolean"
default:
return "string"
}
}
F
function
codeToStr
Parameters
code
int
Returns
string
pkg/openapi/openapi.go:148-154
func codeToStr(code int) string
{
s := ""
s += string(rune('0' + code/100))
s += string(rune('0' + (code/10)%10))
s += string(rune('0' + code%10))
return s
}
F
function
extractTags
Parameters
pkg/openapi/openapi.go:156-169
func extractTags(typ reflect.Type, method, path *string)
{
for i := 0; i < typ.NumField(); i++ {
field := typ.Field(i)
if field.Anonymous {
extractTags(field.Type, method, path)
}
if m := field.Tag.Get("method"); m != "" {
*method = strings.ToLower(m)
}
if p := field.Tag.Get("path"); p != "" {
*path = p
}
}
}
F
function
discoverParameters
Parameters
typ
op
pkg/openapi/openapi.go:171-191
func discoverParameters(typ reflect.Type, op *Operation)
{
for i := 0; i < typ.NumField(); i++ {
field := typ.Field(i)
if field.Anonymous {
discoverParameters(field.Type, op)
continue
}
if q := field.Tag.Get("query"); q != "" {
p := Parameter{Name: q, In: "query", Schema: Schema{Type: goTypeToOpenAPI(field.Type)}}
op.Parameters = append(op.Parameters, p)
}
if p := field.Tag.Get("path"); p != "" {
param := Parameter{Name: p, In: "path", Required: true, Schema: Schema{Type: goTypeToOpenAPI(field.Type)}}
op.Parameters = append(op.Parameters, param)
}
if h := field.Tag.Get("header"); h != "" {
param := Parameter{Name: h, In: "header", Schema: Schema{Type: goTypeToOpenAPI(field.Type)}}
op.Parameters = append(op.Parameters, param)
}
}
}
S
TestEndpoint
pkg/openapi/openapi_test.go:8-12
type TestEndpoint struct
Methods
OpenAPIMeta
Method
Returns
map[string]any
func (*TestEndpoint) OpenAPIMeta() map[string]any
{
return map[string]any{
"summary": "Test endpoint",
"description": "A test endpoint",
}
}
Fields
| Name | Type | Description |
|---|---|---|
| Meta | struct{} | method:"GET" path:"/api/v1/test" |
| Name | string | query:"name" |
| Age | int | query:"age" |
F
function
TestBuild_BasicDocument
Parameters
t
pkg/openapi/openapi_test.go:21-53
func TestBuild_BasicDocument(t *testing.T)
{
doc, err := Build("Test API", "1.0.0", &TestEndpoint{})
if err != nil {
t.Fatalf("Build: %v", err)
}
var result Document
if err := json.Unmarshal(doc, &result); err != nil {
t.Fatalf("Unmarshal: %v", err)
}
if result.OpenAPI != "3.0.3" {
t.Errorf("OpenAPI = %q, want 3.0.3", result.OpenAPI)
}
if result.Info.Title != "Test API" {
t.Errorf("Title = %q, want Test API", result.Info.Title)
}
if result.Info.Version != "1.0.0" {
t.Errorf("Version = %q, want 1.0.0", result.Info.Version)
}
pathItem, ok := result.Paths["/api/v1/test"]
if !ok {
t.Fatal("path /api/v1/test not found")
}
op, ok := pathItem["get"]
if !ok {
t.Fatal("method get not found")
}
if op.Summary != "Test endpoint" {
t.Errorf("Summary = %q, want Test endpoint", op.Summary)
}
}
F
function
TestBuild_AutoParameters
Parameters
t
pkg/openapi/openapi_test.go:55-75
func TestBuild_AutoParameters(t *testing.T)
{
doc, err := Build("Test", "1.0.0", &TestEndpoint{})
if err != nil {
t.Fatalf("Build: %v", err)
}
var result Document
json.Unmarshal(doc, &result)
op := result.Paths["/api/v1/test"]["get"]
foundQuery := false
for _, p := range op.Parameters {
if p.Name == "name" && p.In == "query" {
foundQuery = true
}
}
if !foundQuery {
t.Error("expected query parameter 'name'")
}
}
F
function
TestBuild_NoTags
Parameters
t
pkg/openapi/openapi_test.go:77-83
func TestBuild_NoTags(t *testing.T)
{
type NoTags struct{}
_, err := Build("Test", "1.0.0", &NoTags{})
if err != nil {
t.Fatalf("Build: %v", err)
}
}
F
function
TestGoTypeToOpenAPI
Parameters
t
pkg/openapi/openapi_test.go:85-101
func TestGoTypeToOpenAPI(t *testing.T)
{
tests := []struct {
kind string
goType string
want string
}{
{"int", "int", "integer"},
{"string", "string", "string"},
{"float64", "float64", "number"},
{"bool", "bool", "boolean"},
}
for _, tt := range tests {
t.Run(tt.kind, func(t *testing.T) {
_ = tt.want
})
}
}