Docs Menu
Docs Home
/ /
API de GraphQL

Definir un solucionador personalizado

Puedes definir resolvedores personalizados que extiendan la API de GraphQL para los casos de uso de tu aplicación. Los resolvedores personalizados te permiten definir nuevas operaciones de nivel raíz más complejas o específicas que los resolvedores de consultas y mutaciones generados. También puedes agregar nuevos campos calculados a los tipos de documento generados que evalúan dinámicamente un resultado cada vez que una operación lee un documento del tipo extendido.

1

En la interfaz de usuario de App Services, haga clic en GraphQL en la barra lateral de navegación y luego seleccione la pestaña Custom Resolvers.

Haga clic en el botón Add a Custom Resolver para abrir la pantalla de configuración de un nuevo solucionador personalizado.

La pantalla de solucionadores personalizados en la interfaz de usuario de App Services
2

Especifique el nombre de App Services para el solucionador en la entrada GraphQL Field Name. App Services expone el solucionador personalizado en su tipo principal con este nombre, por lo que este debe describir la función del solucionador de forma útil para los desarrolladores que trabajan con la API GraphQL.

3

App Services expone cada solucionador personalizado como un campo de un tipo principal. Este tipo principal puede ser unaconsulta de nivel raíz, una mutación o un tipo de documento generado.

En el menú desplegable Parent Type, seleccione una de las siguientes opciones:

Opción
Descripción

Query

El resolver es un nivel raíz query operación:

Ejemplo

Un solucionador personalizado para una consulta denominada myCustomQuery tiene el siguiente esquema generado:

type Query {
myCustomQuery: DefaultPayload
...
}

Mutation

El solucionador es una operación de nivel raíz mutation:

Ejemplo

Un solucionador personalizado para una mutación llamada myCustomMutation tiene el siguiente esquema generado:

type Mutation {
myCustomMutation: DefaultPayload
...
}

Document Type

El resolutor es una propiedad computada en el tipo de documento especificado. Cualquier query o mutación que devuelva el tipo de documento también puede solicitar propiedades computadas definidas por resolutores personalizados en el tipo.

Ejemplo

Un resolvedor personalizado que define una propiedad calculada en el tipo Task llamada myCustomTaskProperty tiene el siguiente esquema generado:

type Task {
myCustomTaskProperty: DefaultPayload
...
}
4

Un resolvedor personalizado puede aceptar parámetros de entrada de la consulta o mutación entrante. Puede usar un tipo de entrada generado previamente o definir uno nuevo específicamente para el resolvedor.

Si especifica un tipo de entrada, App Services expone el parámetro input en la definición del esquema GraphQL generada por el solucionador personalizado como un parámetro opcional que acepta el tipo de entrada especificado. Si no especifica un tipo de entrada, el solucionador personalizado no acepta ningún argumento.

En el menú desplegable Input Type, seleccione una de las siguientes opciones:

Opción
Descripción

None

El resolver no acepta ninguna entrada.

Ejemplo

Un solucionador personalizado llamado myCustomQuery que no acepta una entrada tiene el siguiente esquema generado:

type Query {
myCustomQuery: DefaultPayload
...
}

Scalar

El solucionador utiliza un tipo escalar existente del esquema GraphQL generado.

En el segundo campo desplegable, elige un único escalar o un arreglo de múltiples escalares del mismo tipo.

Ejemplo

Un solucionador personalizado llamado myCustomQuery que usa la opción Scalar Type para especificar un tipo de entrada de DateTiem tiene el siguiente esquema generado:

type Query {
myCustomQuery(input: DateTime): DefaultPayload
...
}

Existing Type

El solucionador utiliza un tipo de entrada existente del esquema GraphQL generado.

En la segunda entrada desplegable, seleccione un solo objeto de entrada o una matriz de múltiples objetos de entrada del mismo tipo.

Ejemplo

Un solucionador personalizado llamado myCustomQuery que usa la opción Existing Type para especificar un tipo de entrada de TaskInsertInput tiene el siguiente esquema generado:

type Query {
myCustomQuery(input: TaskInsertInput): DefaultPayload
...
}

Custom Type

App Services genera un nuevo tipo de entrada específicamente para el solucionador, basándose en un esquema definido por el usuario. El esquema debe ser un object que contenga al menos una propiedad y un title campo que defina un nombre único para el tipo de entrada generado.

Una configuración de resolución personalizada para un tipo de entrada personalizado.

Ejemplo

Un solucionador personalizado llamado myCustomQuery que usa la opción Custom Type con un tipo de entrada llamado MyCustomQueryInput tiene el siguiente esquema generado:

input MyCustomQueryInput {
someArgument: String;
}
type Query {
myCustomQuery(input: MyCustomQueryInput): DefaultPayload
...
}
5

Todos los resolvedores GraphQL deben devolver una carga útil que se ajuste a un tipo específico del esquema. Para un resolvedor personalizado, puede usar un tipo de documento generado previamente, definir un nuevo tipo de carga útil personalizado específicamente para el resolvedor o usar una carga útil predeterminada. App Services incluye el tipo de carga útil especificado en la definición del esquema GraphQL generada por el resolvedor personalizado.

En el menú desplegable Payload Type, seleccione una de las siguientes opciones:

Opción
Descripción

DefaultPayload

El solucionador devuelve el tipo DefaultPayload generado automáticamente que tiene la siguiente firma:

type DefaultPayload {
status: String!
}

El campo status siempre se resolverá en "complete" independientemente del valor de retorno de la función de resolución.

{
status: "complete"
}

Ejemplo

Un solucionador personalizado llamado myCustomQuery que utiliza la opción DefaultPayload tiene el siguiente esquema generado:

type Query {
myCustomQuery: DefaultPayload
...
}

Scalar

El solucionador utiliza un tipo escalar existente del esquema GraphQL generado.

En el segundo campo desplegable, elige un único escalar o un arreglo de múltiples escalares del mismo tipo.

Ejemplo

Un solucionador personalizado llamado myCustomQuery que usa la opción Scalar Type para especificar un tipo de carga útil de DateTime tiene el siguiente esquema generado:

type Query {
myCustomQuery: DateTime
...
}

Existing Type

El solucionador devuelve un tipo de documento existente del esquema GraphQL generado.

En la segunda entrada desplegable, seleccione un solo tipo de documento o una matriz de varios documentos del mismo tipo.

Ejemplo

Un solucionador personalizado llamado myCustomQuery que usa la opción Existing Type para especificar un tipo de entrada de TaskInsertInput tiene el siguiente esquema generado:

Un solucionador personalizado llamado myCustomQuery que usa la opción Existing Type para especificar un tipo de carga útil de [Task] tiene el siguiente esquema generado:

type Query {
myCustomQuery: [Task]
...
}

Custom Type

App Services genera un nuevo tipo de payload específicamente para el resolver según un esquema que tú defines. El esquema debe ser un object que contenga al menos una propiedad y un campo title que defina un nombre único para el tipo de entrada generado.

Una configuración de resolución personalizada que define un nuevo tipo de carga útil personalizado.

Ejemplo

Un solucionador personalizado llamado myCustomQuery que usa la opción Custom Type con un tipo de carga útil llamado MyCustomQueryPayload tiene el siguiente esquema generado:

input MyCustomQueryPayload {
someValue: String;
}
type Query {
myCustomQuery: MyCustomQueryPayload
...
}
6

Cuando un usuario llama a un resolvedor personalizado, App Services ejecuta la función resolvedora y devuelve el resultado, que debe cumplir con el Payload Type del resolvedor.

App Services pasa a la función cualquier dato de entrada de la operación, si corresponde. Si el resolvedor es una propiedad calculada de un tipo de documento, App Services pasa a la función el documento específico en el que se invocó.

Una función de resolución personalizada tiene una de dos firmas posibles, dependiendo de si acepta o no una entrada:

exports = function myCustomResolver(input, source) {
// The `input` parameter that contains any input data provided to the resolver.
// The type and shape of this object matches the resolver's input type.
const { someArgument } = input;
// If the resolver is a computed property, `source` is the parent document.
// Otherwise `source` is undefined.
const { _id, name } = source;
// The return value must conform to the resolver's configured payload type
return {
"someValue": "abc123",
};
}
exports = function myCustomResolver(source) {
// If the resolver is a computed property, `source` is the parent document.
// Otherwise `source` is undefined.
const { _id, name } = parent;
// The return value must conform to the resolver's configured payload type
return {
"someValue": "abc123",
};
}

Para definir la función de resolución, haga clic en el menú desplegable Function y seleccione una función existente o cree una nueva.

7

Una vez configurado el resolver, haga clic en Save e implemente su aplicación. Una vez implementada, puede llamar al resolver personalizado a través de la API de GraphQL.

Considere un panel hipotético que un equipo de ventas utiliza para mostrar diversas estadísticas y otras métricas de rendimiento durante un período determinado. El panel utiliza los solucionadores personalizados de esta sección para gestionar algunos de sus casos de uso específicos.

Todos los solucionadores hacen referencia a documentos Sale, que tienen el siguiente esquema:

type Sale {
_id: ObjectId!
customer_id: String!
year: String!
month: String!
saleTotal: Float!
notes: [String]
}
{
"title": "Sale",
"bsonType": "object",
"required": ["_id", "customer_id", "year", "month", "saleTotal"],
"properties": {
"_id": { "bsonType": "objectId" },
"customer_id": { "bsonType": "string" },
"year": { "bsonType": "string" },
"month": { "bsonType": "string" },
"saleTotal": { "bsonType": "decimal" },
"notes": {
"bsonType": "array",
"items": { "bsonType": "string" }
}
}
}

El tablero hipotético del equipo de ventas utiliza un solucionador de query personalizado que devuelve datos de ventas agregados para un mes específico.

App Services genera definiciones de esquema para los tipos de entrada y carga personalizados del solucionador y agrega el solucionador a su tipo principal, el nivel raíz Query:

type Query {
averageSaleForMonth(input: AverageSaleForMonthInput): AverageSaleForMonthPayload
}
input AverageSalesForMonthInput {
month: String!;
year: String!;
}
type AverageSaleForMonthPayload {
month: String!;
year: String!;
averageSale: Float!;
}

El solucionador utiliza la siguiente configuración:

Opción
Descripción

Parent Type

Query

GraphQL Field Name

averageSaleForMonth

Input Type

Tipo personalizado: AverageSaleForMonthInput

{
"bsonType": "object",
"title": "AverageSaleForMonthInput",
"required": ["month", "year"],
"properties": {
"month": {
"bsonType": "string"
},
"year": {
"bsonType": "string"
}
}
}
input AverageSalesForMonthInput {
month: String!;
year: String!;
}

Payload Type

Tipo personalizado: AverageSaleForMonthPayload

{
"bsonType": "object",
"title": "AverageSaleForMonthPayload",
"required": ["month", "year", "averageSale"],
"properties": {
"month": {
"bsonType": "string"
},
"year": {
"bsonType": "string"
},
"averageSale": {
"bsonType": "decimal"
}
}
}
type AverageSaleForMonthPayload {
month: String!;
year: String!;
averageSale: Float!;
}

Function

exports = async function averageSaleForMonth({ month, year }) {
const cluster = context.services.get("mongodb-atlas");
const sales = cluster.db("corp").collection("sales");
const averageSalePayload = await sales
.aggregate([
{ $match: { month: month, year: year } },
{
$group: {
_id: { month: "$month", year: "$year" },
averageSale: { $avg: "$saleTotal" },
}
},
{
$project: {
month: "$_id.month",
year: "$_id.year",
averageSale: 1
}
}
])
.next();
return averageSalePayload;
};

Para llamar a esta consulta personalizada, puede utilizar la siguiente operación y variables:

query GetAverageSaleForMonth($averageSaleInput: AverageSaleForMonthInput!) {
averageSaleForMonth(input: $averageSaleInput) {
month
year
averageSale
}
}
{
"variables": {
"averageSaleInput": { month: "March", year: "2020" }
}
}

El panel hipotético del equipo de ventas utiliza un solucionador de mutaciones personalizado que agrega una nota de cadena a un documento Sale específico, identificado por su _id.

App Services genera definiciones de esquema para el tipo de entrada personalizado del solucionador y agrega el solucionador a su tipo principal, el nivel raíz Mutation:

type Mutation {
addNoteToSale(input: AddNoteToSaleInput): Sale
}
input AddNoteToSaleInput {
sale_id: ObjectId!;
note: String!;
}

El solucionador utiliza la siguiente configuración:

Opción
Descripción

Parent Type

Mutation

GraphQL Field Name

addNoteToSale

Input Type

Tipo personalizado: AddNoteToSaleInput

{
"bsonType": "object",
"title": "AddNoteToSaleInput",
"required": ["sale_id", "note"],
"properties": {
"sale_id": {
"bsonType": "objectId"
},
"note": {
"bsonType": "string"
}
}
}
input AddNoteToSaleInput {
sale_id: ObjectId!;
note: String!;
}

Payload Type

Tipo existente: Sale

type Sale {
_id: ObjectId!
customer_id: String!
year: String!
month: String!
saleTotal: Float!
notes: [String]
}
{
"title": "Sale",
"bsonType": "object",
"required": ["_id", "customer_id", "year", "month", "saleTotal"],
"properties": {
"_id": { "bsonType": "objectId" },
"customer_id": { "bsonType": "string" },
"year": { "bsonType": "string" },
"month": { "bsonType": "string" },
"saleTotal": { "bsonType": "decimal" },
"notes": {
"bsonType": "array",
"items": { "bsonType": "string" }
}
}
}

Function

exports = async function addNoteToSale({ sale_id, note }) {
const cluster = context.services.get("mongodb-atlas");
const sales = cluster.db("corp").collection("sales");
const sale = await sales.findOneAndUpdate(
{ _id: sale_id },
{ $push: { notes: note } },
{ returnNewDocument: true }
);
return sale;
}

Para llamar a esta consulta personalizada, puede utilizar la siguiente operación y variables:

mutation AddNoteToSale($addNoteToSaleInput: AddNoteToSaleInput) {
addNoteToSale(input: $addNoteToSaleInput) {
_id
customer_id
month
year
saleTotal
notes
}
}
{
"variables": {
"addNoteToSaleInput": {
"sale_id": "5f3c2779796615b661fcdc25",
"note": "This was such a great sale!"
}
}
}

El panel hipotético del equipo de ventas utiliza un solucionador personalizado que añade una nueva propiedad calculada a cada documento Sale. Cuando una operación solicita el campo calculado para un Sale determinado, el solucionador consulta un sistema externo y devuelve los casos de soporte presentados por el cliente asociado.

App Services genera definiciones de esquema para el tipo de carga útil personalizado del solucionador y agrega el solucionador a su tipo principal, Sale:

type Sale {
_id: ObjectId!
customer_id: String!
year: String!
month: String!
saleTotal: Float!
notes: [String]
customerSupportCases: [CustomerSupportCase]
}
type CustomerSupportCase {
caseId: String!
description: String!
}

El solucionador utiliza la siguiente configuración:

Opción
Descripción

Parent Type

Sale

GraphQL Field Name

customerSupportCases

Input Type

Ninguno

Payload Type

Tipo personalizado: [CustomerSupportCase]

{
"bsonType": "array",
"items": {
"title": "CustomerSupportCase",
"bsonType": "object",
"required": ["caseId", "description"],
"properties": {
"caseId": { "bsonType": "string" },
"description": { "bsonType": "string" }
}
}
}
type CustomerSupportCase {
caseId: String!
description: String!
}
type Sale {
_id: ObjectId!
customer_id: String!
year: String!
month: String!
saleTotal: Float!
notes: [String]
customerSupportCases: [CustomerSupportCase]
}

Function

exports = async function customerSupportCases(sale) {
// Return a list of objects from some external system
const cases = await fetchCustomerSupportCases({
customerId: sale.customer_id
});
return cases;
};

Para utilizar esta propiedad calculada personalizada, puede ejecutar la siguiente operación:

query GetSalesWithSupportCases {
sales {
_id
customer_id
year
month
saleTotal
notes
customerSupportCases {
caseId
description
}
}
}

Volver

Tipos de GraphQL, resolutores y operadores

En esta página