Join us at MongoDB.local London on 7 May to unlock new possibilities for your data. Use WEB50 to save 50%.
Register now >
Docs Menu
Docs Home
/ /
API de GraphQL

Definir un resolver 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

Specify App Servicese name for the resolver in the GraphQL Field Name input. App Services exposes the custom resolver in its parent type using this name, so the name should describe what the resolver does in a way that is useful to developers who work with the GraphQL API.

3

App Services exposes every custom resolver as a field on a parent type. The parent type can be a root-level query, mutation, or a generated document type.

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

Opción
Descripción

Query

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

Ejemplo

A custom resolver for a query named myCustomQuery has the following generated schema:

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

A custom resolver can accept input parameters from the incoming query or mutation. You can use an existing generated input type or define a new custom input type specifically for the resolver.

If you specify an input type, App Services exposes the input parameter in the custom resolver's generated GraphQL schema definition as an optional parameter that accepts the specified input type. If you don't specify an input type, the custom resolver does not accept any arguments.

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

Opción
Descripción

None

El resolver no acepta ninguna entrada.

Ejemplo

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

type Query {
myCustomQuery: DefaultPayload
...
}

Scalar

The resolver uses an existing scalar type from the generated GraphQL schema.

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, selecciona 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 que devuelva la función resolutora.

{
status: "complete"
}

Ejemplo

A custom resolver named myCustomQuery that uses the DefaultPayload option has the following generated schema:

type Query {
myCustomQuery: DefaultPayload
...
}

Scalar

The resolver uses an existing scalar type from the generated GraphQL schema.

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

Ejemplo

Un resolver personalizado llamado myCustomQuery que utiliza 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.

In the second dropdown input, select either a single document type or an array of multiple documents of the same type.

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 resolver personalizado llamado myCustomQuery que utiliza 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

A custom resolver named myCustomQuery that uses the Custom Type option with a payload type named MyCustomQueryPayload has the following generated schema:

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.

aplicación Services pasa la función cualquier dato de entrada proveniente de la operación, si corresponde. Si el solucionador es una propiedad calculada en un tipo de documento, aplicación Services pasa la función el documento específico en el que se llamó al solucionador.

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 del resolver, haz clic en el menú desplegable Function y selecciona una función existente o crea 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.

The resolvers all reference Sale documents, which have the following schema:

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;
};

To call this custom query, you could use the following operation and variables:

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

The sales team's hypothetical dashboard uses a custom mutation resolver that adds a string note to a specific Sale document, identified by its _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;
}

To call this custom query, you could use the following operation and 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 tablero hipotético del equipo de ventas utiliza un resolver personalizado que añade una nueva propiedad computada a cada documento Sale. Cuando una operación solicita el campo computado para un Sale dado, el resolver consulta un sistema externo y devuelve los casos de soporte archivados 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