Mutaciones Transaccionales
Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →
En esta sección, continuamos con el ejemplo de GraphQL explicando cómo configurar nuestras mutaciones GraphQL para que sean transaccionales. Esto significa envolver automáticamente nuestras mutaciones GraphQL con una transacción de base de datos, confirmándola al final o deshaciéndola si ocurre un error de GraphQL.
Clonar el código (opcional)
El código de este tutorial está disponible en github.com/a8m/ent-graphql-example,
con etiquetas (usando Git) en cada paso. Si prefieres saltarte la configuración básica y comenzar con la versión inicial del servidor
GraphQL, puedes clonar el repositorio y hacer checkout de v0.1.0 de la siguiente forma:
git clone git@github.com:a8m/ent-graphql-example.git
cd ent-graphql-example
go run ./cmd/todo/
Uso
La extensión GraphQL proporciona un manejador llamado entgql.Transactioner que ejecuta cada mutación GraphQL en una
transacción. El cliente inyectado en el resolver es un ent.Client transaccional,
por lo que los resolvers GraphQL que usen ent.Client no requerirán modificaciones. Para añadirlo a nuestra aplicación de lista de tareas,
seguimos estos pasos:
1. Edita cmd/todo/main.go y añade el manejador entgql.Transactioner durante la inicialización del servidor GraphQL
de la siguiente forma:
srv := handler.NewDefaultServer(todo.NewSchema(client))
+srv.Use(entgql.Transactioner{TxOpener: client})
2. Luego, en las mutaciones GraphQL, usa el cliente del contexto así:
}
+func (mutationResolver) CreateTodo(ctx context.Context, input ent.CreateTodoInput) (*ent.Todo, error) {
+ client := ent.FromContext(ctx)
+ return client.Todo.Create().SetInput(input).Save(ctx)
-func (r *mutationResolver) CreateTodo(ctx context.Context, input ent.CreateTodoInput) (*ent.Todo, error) {
- return r.client.Todo.Create().SetInput(input).Save(ctx)
}
Niveles de Aislamiento
Si deseas ajustar el nivel de aislamiento de la transacción, puedes implementar tu propio TxOpener. Por ejemplo:
srv.Use(entgql.Transactioner{
TxOpener: entgql.TxOpenerFunc(func(ctx context.Context) (context.Context, driver.Tx, error) {
tx, err := client.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelRepeatableRead})
if err != nil {
return nil, nil, err
}
ctx = ent.NewTxContext(ctx, tx)
ctx = ent.NewContext(ctx, tx.Client())
return ctx, tx, nil
}),
})
Omitir Operaciones
Por defecto, entgql.Transactioner envuelve todas las mutaciones en una transacción. Sin embargo, existen mutaciones u operaciones
que no requieren acceso a la base de datos o necesitan un manejo especial. En estos casos, puedes indicar a entgql.Transactioner
que omita la transacción configurando una función personalizada SkipTxFunc o usando una de las integradas.
srv.Use(entgql.Transactioner{
TxOpener: client,
// Skip the given operation names from running under a transaction.
SkipTxFunc: entgql.SkipOperations("operation1", "operation2"),
})
srv.Use(entgql.Transactioner{
TxOpener: client,
// Skip if the operation has a mutation field with the given names.
SkipTxFunc: entgql.SkipIfHasFields("field1", "field2"),
})
srv.Use(entgql.Transactioner{
TxOpener: client,
// Custom skip function.
SkipTxFunc: func(*ast.OperationDefinition) bool {
// ...
},
})
¡Excelente! Con pocas líneas de código, nuestra aplicación ahora soporta mutaciones transaccionales automáticas. Continúa con la siguiente sección donde explicamos cómo extender el generador de código Ent y generar tipos de entrada GraphQL para nuestras mutaciones GraphQL.