Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →
En resumen
Hemos añadido una nueva integración a la extensión GraphQL de Ent que genera filtros GraphQL con seguridad de tipos (predicados Where)
a partir de un ent/schema, permitiendo mapear consultas GraphQL a consultas Ent de forma transparente.
Por ejemplo, para obtener todos los elementos de tareas COMPLETED, podemos ejecutar lo siguiente:
query QueryAllCompletedTodos {
todos(
where: {
status: COMPLETED,
},
) {
edges {
node {
id
}
}
}
}
Los filtros GraphQL generados siguen la sintaxis de Ent. Esto significa que la siguiente consulta también es válida:
query FilterTodos {
todos(
where: {
or: [
{
hasParent: false,
status: COMPLETED,
},
{
status: IN_PROGRESS,
hasParentWith: {
priorityLT: 1,
statusNEQ: COMPLETED,
},
}
]
},
) {
edges {
node {
id
}
}
}
}
Antecedentes
Muchas bibliotecas que manejan datos en Go utilizan interfaces vacías (interface{})
y reflexión en tiempo de ejecución para mapear datos a campos de estructuras. Además del impacto en rendimiento,
la principal desventaja para los equipos es la pérdida de seguridad de tipos.
Cuando las APIs son explícitas y conocidas en tiempo de compilación (o incluso mientras escribimos), la retroalimentación sobre errores es casi inmediata. Muchos defectos se detectan antes y ¡el desarrollo es mucho más divertido!
Ent fue diseñado para ofrecer una excelente experiencia a equipos que trabajan con modelos de datos complejos.
Uno de nuestros principios fundamentales es: "API estática y explícita mediante generación de código".
Esto significa que por cada entidad definida en ent/schema, se genera código con seguridad de tipos
para interactuar eficientemente con los datos. Por ejemplo, en el
Ejemplo de sistema de archivos del repositorio ent,
encontrarás un esquema llamado File:
// File holds the schema definition for the File entity.
type File struct {
ent.Schema
}
// Fields of the File.
func (File) Fields() []ent.Field {
return []ent.Field{
field.String("name"),
field.Bool("deleted").
Default(false),
field.Int("parent_id").
Optional(),
}
}
Al ejecutar el generador de código de Ent, se crean funciones de predicado. Por ejemplo, esta función
para filtrar Files por su campo name:
package file
// .. truncated ..
// Name applies the EQ predicate on the "name" field.
func Name(v string) predicate.File {
return predicate.File(func(s *sql.Selector) {
s.Where(sql.EQ(s.C(FieldName), v))
})
}
GraphQL es un lenguaje de consulta para APIs creado en Facebook. Al igual que Ent, modela datos como grafos y facilita consultas con seguridad de tipos. Hace un año, lanzamos una integración entre Ent y GraphQL. Similar a la Integración gRPC, su objetivo es permitir crear servidores API que mapeen operaciones Ent para consultar y modificar datos.
Generación Automática de Filtros GraphQL
En una encuesta reciente, la integración Ent+GraphQL fue destacada como una de las funcionalidades más valoradas del proyecto. Hasta ahora permitía consultas básicas, pero hoy anunciamos una función que abrirá nuevos casos de uso: "Generación Automática de Filtros GraphQL".
Como vimos, el generador de Ent crea funciones de predicado para filtrar datos explícitamente. Este poder no estaba disponible (automáticamente) en la integración GraphQL hasta ahora. Con esta nueva función, añadiendo una línea de configuración, los desarrolladores pueden agregar "Tipos de Entrada de Filtro" completos a su esquema GraphQL. Además, el sistema traduce estos predicados a consultas Ent en tiempo de ejecución. Veámoslo en acción:
Generación de Tipos de Entrada de Filtro
Para generar filtros de entrada (ej. TodoWhereInput) para cada tipo en tu paquete ent/schema,
edita el archivo ent/entc.go así:
// +build ignore
package main
import (
"log"
"entgo.io/contrib/entgql"
"entgo.io/ent/entc"
"entgo.io/ent/entc/gen"
)
func main() {
ex, err := entgql.NewExtension(
entgql.WithWhereFilters(true),
entgql.WithConfigPath("../gqlgen.yml"),
entgql.WithSchemaPath("<PATH-TO-GRAPHQL-SCHEMA>"),
)
if err != nil {
log.Fatalf("creating entgql extension: %v", err)
}
err = entc.Generate("./schema", &gen.Config{}, entc.Extensions(ex))
if err != nil {
log.Fatalf("running ent codegen: %v", err)
}
}
Si eres nuevo en Ent y GraphQL, sigue el Tutorial de Inicio.
A continuación, ejecuta go generate ./ent/.... Observa que Ent ha generado <T>WhereInput para cada tipo en tu esquema. Ent actualizará automáticamente el esquema GraphQL, así que no necesitas autobindearlos manualmente con gqlgen. Por ejemplo:
// TodoWhereInput represents a where input for filtering Todo queries.
type TodoWhereInput struct {
Not *TodoWhereInput `json:"not,omitempty"`
Or []*TodoWhereInput `json:"or,omitempty"`
And []*TodoWhereInput `json:"and,omitempty"`
// "created_at" field predicates.
CreatedAt *time.Time `json:"createdAt,omitempty"`
CreatedAtNEQ *time.Time `json:"createdAtNEQ,omitempty"`
CreatedAtIn []time.Time `json:"createdAtIn,omitempty"`
CreatedAtNotIn []time.Time `json:"createdAtNotIn,omitempty"`
CreatedAtGT *time.Time `json:"createdAtGT,omitempty"`
CreatedAtGTE *time.Time `json:"createdAtGTE,omitempty"`
CreatedAtLT *time.Time `json:"createdAtLT,omitempty"`
CreatedAtLTE *time.Time `json:"createdAtLTE,omitempty"`
// "status" field predicates.
Status *todo.Status `json:"status,omitempty"`
StatusNEQ *todo.Status `json:"statusNEQ,omitempty"`
StatusIn []todo.Status `json:"statusIn,omitempty"`
StatusNotIn []todo.Status `json:"statusNotIn,omitempty"`
// .. truncated ..
}
"""
TodoWhereInput is used for filtering Todo objects.
Input was generated by ent.
"""
input TodoWhereInput {
not: TodoWhereInput
and: [TodoWhereInput!]
or: [TodoWhereInput!]
"""created_at field predicates"""
createdAt: Time
createdAtNEQ: Time
createdAtIn: [Time!]
createdAtNotIn: [Time!]
createdAtGT: Time
createdAtGTE: Time
createdAtLT: Time
createdAtLTE: Time
"""status field predicates"""
status: Status
statusNEQ: Status
statusIn: [Status!]
statusNotIn: [Status!]
# .. truncated ..
}
Para completar la integración, necesitamos hacer dos cambios más:
1. Edita el esquema GraphQL para aceptar los nuevos tipos de filtros:
type Query {
todos(
after: Cursor,
first: Int,
before: Cursor,
last: Int,
orderBy: TodoOrder,
where: TodoWhereInput,
): TodoConnection!
}
2. Utiliza los nuevos tipos de filtros en los resolvers de GraphQL:
func (r *queryResolver) Todos(ctx context.Context, after *ent.Cursor, first *int, before *ent.Cursor, last *int, orderBy *ent.TodoOrder, where *ent.TodoWhereInput) (*ent.TodoConnection, error) {
return r.client.Todo.Query().
Paginate(ctx, after, first, before, last,
ent.WithTodoOrder(orderBy),
ent.WithTodoFilter(where.Filter),
)
}
Especificación de Filtros
Como mencionamos antes, con los nuevos tipos de filtros GraphQL, puedes expresar los mismos filtros de Ent que usas en tu código Go.
Conjunción, disyunción y negación
Los operadores Not, And y Or pueden añadirse usando los campos not, and y or. Por ejemplo:
{
or: [
{
status: COMPLETED,
},
{
not: {
hasParent: true,
status: IN_PROGRESS,
}
}
]
}
Cuando se proporcionan múltiples campos de filtro, Ent añade implícitamente el operador And.
{
status: COMPLETED,
textHasPrefix: "GraphQL",
}
La consulta anterior producirá el siguiente query de Ent:
client.Todo.
Query().
Where(
todo.And(
todo.StatusEQ(todo.StatusCompleted),
todo.TextHasPrefix("GraphQL"),
)
).
All(ctx)
Filtros de relaciones (edges)
Los predicados de relaciones (edges) pueden expresarse con la misma sintaxis de Ent:
{
hasParent: true,
hasChildrenWith: {
status: IN_PROGRESS,
}
}
La consulta anterior producirá el siguiente query de Ent:
client.Todo.
Query().
Where(
todo.HasParent(),
todo.HasChildrenWith(
todo.StatusEQ(todo.StatusInProgress),
),
).
All(ctx)
Ejemplo de Implementación
Existe un ejemplo funcional en github.com/a8m/ent-graphql-example.
Conclusión
Como mencionamos antes, Ent tiene como principio fundamental crear "APIs estáticamente tipadas y explícitas mediante generación de código". Con la generación automática de filtros GraphQL, reforzamos esta idea para brindar a los desarrolladores la misma experiencia de desarrollo explícita y tipada en la capa RPC.
¿Tienes preguntas? ¿Necesitas ayuda para comenzar? Ú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