Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →
En un artículo anterior,
te presentamos elk, una extensión de Ent
que permite generar una API HTTP CRUD completamente funcional en Go a partir de tu esquema. En el artículo de hoy
me gustaría presentarte una nueva y reluciente característica que ha llegado recientemente a elk:
un generador totalmente compatible de la Especificación OpenAPI (OAS).
OAS (anteriormente conocida como Swagger Specification) es una especificación técnica que define una descripción estándar de interfaz, independiente del lenguaje, para APIs REST. Esto permite tanto a humanos como a herramientas automatizadas comprender el servicio descrito sin necesidad del código fuente o documentación adicional. Combinado con las herramientas Swagger, puedes generar código boilerplate tanto para servidor como para cliente en más de 20 lenguajes, simplemente pasando el archivo OAS.
Empezando
El primer paso es añadir el paquete elk a tu proyecto:
go get github.com/masseelch/elk@latest
elk utiliza la API de Extensiones de Ent para integrarse con la generación
de código de Ent. Esto requiere que usemos el paquete entc (ent codegen) como se describe
aquí para generar el código de nuestro proyecto. Sigue
estos dos pasos para activarlo y configurar Ent para trabajar con la extensión elk:
1. Crea un nuevo archivo Go llamado ent/entc.go y pega el siguiente contenido:
// +build ignore
package main
import (
"log"
"entgo.io/ent/entc"
"entgo.io/ent/entc/gen"
"github.com/masseelch/elk"
)
func main() {
ex, err := elk.NewExtension(
elk.GenerateSpec("openapi.json"),
)
if err != nil {
log.Fatalf("creating elk extension: %v", err)
}
err = entc.Generate("./schema", &gen.Config{}, entc.Extensions(ex))
if err != nil {
log.Fatalf("running ent codegen: %v", err)
}
}
2. Edita el archivo ent/generate.go para ejecutar el archivo ent/entc.go:
package ent
//go:generate go run -mod=mod entc.go
¡Con estos pasos completados, todo está listo para generar un archivo OAS desde tu esquema! Si eres nuevo en Ent y quieres aprender más sobre cómo conectar con diferentes tipos de bases de datos, ejecutar migraciones o trabajar con entidades, dirígete al Tutorial de Configuración.
Generar un archivo OAS
El primer paso hacia nuestro archivo OAS es crear un gráfico de esquema Ent:
go run -mod=mod entgo.io/ent/cmd/ent new Fridge Compartment Item
Para demostrar las capacidades de generación OAS de elk, construiremos juntos una aplicación de ejemplo.
Supongamos que tengo varios frigoríficos con múltiples compartimentos, y mi pareja y yo queremos conocer su
contenido en todo momento. Para proporcionarnos esta información increíblemente útil, crearemos un servidor
en Go con una API RESTful. Para facilitar la creación de aplicaciones cliente que puedan comunicarse con
nuestro servidor, crearemos un archivo de Especificación OpenAPI que describa su API. Una vez que lo tengamos,
¡podremos construir un frontend para gestionar frigoríficos y contenidos en el lenguaje que elijamos usando
Swagger Codegen! Puedes encontrar un ejemplo que usa docker para generar un cliente
aquí.
Creemos nuestro esquema:
package schema
import (
"entgo.io/ent"
"entgo.io/ent/schema/edge"
"entgo.io/ent/schema/field"
)
// Fridge holds the schema definition for the Fridge entity.
type Fridge struct {
ent.Schema
}
// Fields of the Fridge.
func (Fridge) Fields() []ent.Field {
return []ent.Field{
field.String("title"),
}
}
// Edges of the Fridge.
func (Fridge) Edges() []ent.Edge {
return []ent.Edge{
edge.To("compartments", Compartment.Type),
}
}
package schema
import (
"entgo.io/ent"
"entgo.io/ent/schema/edge"
"entgo.io/ent/schema/field"
)
// Compartment holds the schema definition for the Compartment entity.
type Compartment struct {
ent.Schema
}
// Fields of the Compartment.
func (Compartment) Fields() []ent.Field {
return []ent.Field{
field.String("name"),
}
}
// Edges of the Compartment.
func (Compartment) Edges() []ent.Edge {
return []ent.Edge{
edge.From("fridge", Fridge.Type).
Ref("compartments").
Unique(),
edge.To("contents", Item.Type),
}
}
package schema
import (
"entgo.io/ent"
"entgo.io/ent/schema/edge"
"entgo.io/ent/schema/field"
)
// Item holds the schema definition for the Item entity.
type Item struct {
ent.Schema
}
// Fields of the Item.
func (Item) Fields() []ent.Field {
return []ent.Field{
field.String("name"),
}
}
// Edges of the Item.
func (Item) Edges() []ent.Edge {
return []ent.Edge{
edge.From("compartment", Compartment.Type).
Ref("contents").
Unique(),
}
}
Ahora, generemos el código de Ent y el archivo OAS.
go generate ./...
Además de los archivos que Ent genera normalmente, se ha creado otro archivo llamado openapi.json. Copia su
contenido y pégalo en el Editor Swagger. Deberías ver tres grupos: Compartment,
Item y Fridge.

Swagger Editor Example
Si abres la pestaña de operación POST en el grupo Fridge, verás una descripción de los datos esperados en la solicitud y todas las respuestas posibles. ¡Genial!

POST operation on Fridge
Configuración básica
La descripción de nuestra API aún no refleja su propósito. ¡Vamos a cambiarlo! elk ofrece constructores de configuración fáciles de usar para personalizar el archivo OAS generado. Abre ent/entc.go y actualiza el título y la descripción de nuestra Fridge API:
//go:build ignore
// +build ignore
package main
import (
"log"
"entgo.io/ent/entc"
"entgo.io/ent/entc/gen"
"github.com/masseelch/elk"
)
func main() {
ex, err := elk.NewExtension(
elk.GenerateSpec(
"openapi.json",
// It is a Content-Management-System ...
elk.SpecTitle("Fridge CMS"),
// You can use CommonMark syntax (https://commonmark.org/).
elk.SpecDescription("API to manage fridges and their cooled contents. **ICY!**"),
elk.SpecVersion("0.0.1"),
),
)
if err != nil {
log.Fatalf("creating elk extension: %v", err)
}
err = entc.Generate("./schema", &gen.Config{}, entc.Extensions(ex))
if err != nil {
log.Fatalf("running ent codegen: %v", err)
}
}
Al volver a ejecutar el generador de código se creará un archivo OAS actualizado que puedes copiar y pegar en el Swagger Editor.

Updated API Info
Configuración de operaciones
No queremos exponer endpoints para eliminar frigoríficos (¿en serio, a quién se le ocurriría?). Afortunadamente, elk nos permite configurar qué endpoints generar y cuáles ignorar. La política predeterminada de elk es exponer todas las rutas. Puedes cambiar este comportamiento para no exponer ninguna ruta excepto las solicitadas explícitamente, o simplemente indicar a elk que excluya la operación DELETE en Fridge usando una elk.SchemaAnnotation:
// Annotations of the Fridge.
func (Fridge) Annotations() []schema.Annotation {
return []schema.Annotation{
elk.DeletePolicy(elk.Exclude),
}
}
¡Y voilà! La operación DELETE ha desaparecido.

DELETE operation is gone
Para más información sobre cómo funcionan las políticas de elk y lo que puedes hacer con ellas, consulta la godoc.
Extender la especificación
Lo más interesante en este ejemplo sería conocer el contenido actual de un frigorífico. Puedes personalizar el OAS generado hasta donde desees usando Hooks. Sin embargo, esto excedería el alcance de esta publicación. Un ejemplo de cómo añadir un endpoint fridges/{id}/contents al archivo OAS generado puede encontrarse aquí.
Generar un servidor compatible con OAS
Al principio prometí que crearíamos un servidor que se comporte como describe el OAS. elk lo hace fácil: solo debes llamar a elk.GenerateHandlers() al configurar la extensión:
[...]
func main() {
ex, err := elk.NewExtension(
elk.GenerateSpec(
[...]
),
+ elk.GenerateHandlers(),
)
[...]
}
A continuación, vuelve a ejecutar la generación de código:
go generate ./...
Observa que se ha creado un nuevo directorio llamado ent/http.
» tree ent/http
ent/http
├── create.go
├── delete.go
├── easyjson.go
├── handler.go
├── list.go
├── read.go
├── relations.go
├── request.go
├── response.go
└── update.go
0 directories, 10 files
Puedes iniciar el servidor generado con este sencillo main.go:
package main
import (
"context"
"log"
"net/http"
"<your-project>/ent"
elk "<your-project>/ent/http"
_ "github.com/mattn/go-sqlite3"
"go.uber.org/zap"
)
func main() {
// Create the ent client.
c, err := ent.Open("sqlite3", "file:ent?mode=memory&cache=shared&_fk=1")
if err != nil {
log.Fatalf("failed opening connection to sqlite: %v", err)
}
defer c.Close()
// Run the auto migration tool.
if err := c.Schema.Create(context.Background()); err != nil {
log.Fatalf("failed creating schema resources: %v", err)
}
// Start listen to incoming requests.
if err := http.ListenAndServe(":8080", elk.NewHandler(c, zap.NewExample())); err != nil {
log.Fatal(err)
}
}
go run -mod=mod main.go
Nuestro servidor de Fridge API está en funcionamiento. Con el archivo OAS generado y las herramientas Swagger, ahora puedes generar un stub de cliente en cualquier lenguaje soportado y olvidarte de escribir un cliente RESTful... ¡para siempre!
Conclusión
En esta publicación presentamos una nueva característica de elk: la generación automática de Especificaciones OpenAPI. Esta función conecta las capacidades de generación de código de Ent con el ecosistema de herramientas OpenAPI/Swagger.
¿Tienes preguntas? ¿Necesitas ayuda para empezar? Únete a nuestro servidor de Discord o canal de Slack.
- Suscríbete a nuestro Newsletter
- Síguenos en Twitter
- Únete a #ent en Gophers Slack
- Únete al Ent Discord Server