Skip to content
Documentation & entrest itself are a work in progress (expect breaking changes). Check out the GitHub Project to contribute.

Extending the Spec

You may want to extend the resulting OpenAPI spec, to add additional endpoints, tweak the schema, add security schemes, changelog/information, etc. entrest allows a few different ways of extending the OpenAPI spec.

SpecFromPath

Configuration option SpecFromPath allows you to provide a path to a JSON file containing the base OpenAPI spec. This is useful if you want to start with a base spec, and then add additional endpoints/security schemes/etc. This is the simplest option to managing extensions that is much less tedious than dealing with the Spec option.

internal/database/entc.go
func main() {
ex, err := entrest.NewExtension(&entrest.Config{
// The path here is dependent on where your file that has "go:generate" is. Take a look at the "kitchensink"
// example for where the base-openapi.json file is located.
SpecFromPath: "../base-openapi.json",
})
// [...]
}

Base OpenAPI spec from our kitchensink example, where we register a /version endpoint and associated schema:

_examples/kitchensink/base-openapi.json
{
"info": {
"title": "Kitchen Sink EntGo Rest API",
"version": "1.0.0"
},
"paths": {
"/version": {
"get": {
"tags": [
"Meta"
],
"summary": "Get service version",
"description": "Get the version of the service.",
"operationId": "getServiceVersion",
"responses": {
"200": {
"description": "Service version information was found.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"name": {
"description": "Name of cli tool.",
"type": "string"
},
"build_version": {
"description": "Build version.",
"type": "string"
},
"build_commit": {
"description": "VCS commit SHA.",
"type": "string"
},
"build_date": {
"description": "VCS commit date.",
"type": "string"
},
"command": {
"description": "Executable name where the command was called from.",
"type": "string"
},
"go_version": {
"description": "Version of Go that produced this binary.",
"type": "string"
},
"os": {
"description": "Operating system for this build.",
"type": "string"
},
"arch": {
"description": "CPU Architecture for this build.",
"type": "string"
}
},
"required": [
"name",
"go_version",
"os",
"arch"
]
}
}
}
}
}
}
}
}
}

Take a look at the resulting OpenAPI spec, which includes the /version endpoint and associated schema here.

Request Headers

TODO

Response Headers

TODO

Error Responses

TODO

Spec Configuration Option

Configuration option Spec allows you to provide a custom OpenAPI spec through the ogen.Spec type provided by ogen. This is more of an advanced option, as it allows you to use additional Go logic to add additional generated endpoints or similar. This spec is effectively treated like the "base" in which the generated spec is merged into. A basic example:

internal/database/entc.go
func main() {
ex, err := entrest.NewExtension(&entrest.Config{
Spec: &ogen.Spec{
Info: ogen.Info{
Title: "My Sample API",
Description: "This is a sample API.",
},
Components: &ogen.Components{
Schemas: map[string]*ogen.Schema{
"FooBar": {Type: "string"},
},
},
},
})
// [...]
}

PreGenerateHook and PostGenerateHook

Configuration option PreGenerateHook and PostGenerateHook are similar to the Spec option, but you get access to the ent graph. Primarily useful if you need to extend the spec with ent-specific information, or you want to reuse content from the generated configuration, and build upon it.

Example with a PreGenerateHook:

internal/database/entc.go
func main() {
ex, err := entrest.NewExtension(&entrest.Config{
PreGenerateHook: func(g *gen.Graph, spec *ogen.Spec) error {
// Example:
spec.Components.Schemas["FooBar"] = &ogen.Schema{Type: "string"}
return nil
},
})
// [...]
}

Same thing with a PostGenerateHook, but it runs after the spec has been generated:

internal/database/entc.go
func main() {
ex, err := entrest.NewExtension(&entrest.Config{
PostGenerateHook: func(g *gen.Graph, spec *ogen.Spec) error {
// Example:
spec.Components.Schemas["FooBar"] = &ogen.Schema{Type: "string"}
return nil
},
})
// [...]
}