@zorro3

Как предотвратить ошибку graphQL и выполнить мутацию по scalar type в схеме?

У меня есть scalar type "ArbitraryObject" это кастомный тип для того, что бы иметь возможность пулучать любые ключи в объекте. Я успешно получаю данные на get, но не могу создать или обновить элемент, получаю такую ошибку: "Field "parameters" must not have a selection since type "ArbitraryObject" has no subfields.". code: "GRAPHQL_VALIDATION_FAILED".
Как избежать эту ошибку и иметь возможность создавать элемент?

import * as log from "../../logger"
import { getGrpcRequestContext } from "../../clients"
import { struct } from "pb-util"
import { GraphQLScalarType } from "graphql"
import { Kind } from "graphql/language"

export const typeDefs = `
    scalar ArbitraryObject

    enum FieldTransformOperation {
        COPY
        EXTRACT_SUBSTRING
        EXTRACT_REGULAR_EXPRESSION
    }
    
    type ParametersTransform {
        preTagField: String
        substringReplacements: ArbitraryObject
        groupNamesToTagsMap: ArbitraryObject
        replacementGroupsMap: ArbitraryObject
        targetGroup: String
    }

    type FieldTransform {
        sourceKey: String
        operation: FieldTransformOperation
        parameters: ParametersTransform
    }

    type Ingest {
        name: String
        requiredKeys: [String]
        fieldTransforms: [FieldTransform]
    }  

    input PolicyByNameInput {
        name: String!
    }

    input ParametersTransformInput {
        preTagField: String
        substringReplacements: ArbitraryObject
        groupNamesToTagsMap: ArbitraryObject
        replacementGroupsMap: ArbitraryObject
        targetGroup: String
    }

    input FieldTransformInput {
        sourceKey: String
        operation: FieldTransformOperation
        parameters: ParametersTransformInput
    }
    
    input IngestInput {
        name: String
        requiredKeys: [String]
        fieldTransforms: [FieldTransformInput]
    }

    extend type Query {
        defaultIngest(input: PolicyByNameInput): Ingest
    }

    extend type Mutation {
        createIngest(input: IngestInput): Ingest
        updateIngest(input: IngestInput): Ingest
    }
`

// custom Object type for the possibility to have Object with any keys
const ObjectScalarType = () => new GraphQLScalarType({
    name: 'ArbitraryObject',
    description: 'Arbitrary object',
    parseValue: (value) => {
        try {
            return JSON.stringify(value)
        } catch (e) {
            log.contextLogger(e).error(e, "Failed to parse field transform additional data")
            return null
        }
    },
    serialize: (value) => {
            if (value === 'object' || value.length) {
                return value
            } else {
                try {
                   return  JSON.parse(value)
                } catch (e) {
                    log.contextLogger(e).error(e, "Failed to serialize field transform additional data")
                    return null
                }
            }
    },
    parseLiteral: (ast) => {
        switch (ast.kind) {
            case Kind.STRING: return JSON.parse(ast.value)
            case Kind.OBJECT: throw new Error(`failed to parse arbitrary object for ObjectScalarType`)
            default: return null
        }
    }
})

async function getDefaultIngest(name, ctx) {
    log.contextLogger(ctx).debug({ name }, "Getting default policy ingest")
    const requestContext = getGrpcRequestContext(ctx)
    try {
        return await ctx.dataSources.policySvc.GetDefaultIngest(
            name, requestContext
        )
    } catch (e) {
        log.contextLogger(ctx).warn(e, "Failed to get default policy ingest")
    }
}

async function createIngestRequest(ingest, ctx) {
    log.contextLogger(ctx).debug({ ingest }, "Creating custom policy ingest")
    const requestContext = getGrpcRequestContext(ctx)
    try {
        return await ctx.dataSources.policySvc.CreateIngest(
            { ingest }, requestContext
        )
    } catch (e) {
        log.contextLogger(ctx).warn(e, "Failed to create policy ingest")
    }
}

async function updateIngestRequest(ingest, ctx) {
    log.contextLogger(ctx).debug({ ingest }, "Updating custom policy ingest")
    const requestContext = getGrpcRequestContext(ctx)
    try {
        return await ctx.dataSources.policySvc.UpdateIngest(
            { ingest }, requestContext
        )
    } catch (e) {
        log.contextLogger(ctx).warn(e, "Failed to update policy ingest")
    }
}

// encode/decode for grcp struct "parameters"
function getFormattedIngest(data, action) {
    const ingest = data
    if(ingest.fieldTransforms && ingest.fieldTransforms.length) {
        ingest.fieldTransforms = ingest.fieldTransforms.map(field => {
            if(field.parameters) {
                const decodedParams = struct[action](field.parameters)
                return {...field, parameters: decodedParams}
            } else {
                return field
            }
        })
    }
    return ingest
}

export const resolvers = {
    Query: {
        defaultIngest: async (_, { input }, ctx) => {
            const response = await getDefaultIngest(input, ctx)
            return response ? getFormattedIngest(response.ingest, "decode") : null
        },
    Mutation: {
        createIngest: async (_, { input }, ctx) => {
            const formattedInput = getFormattedIngest(input, "encode")
            const response = await createIngestRequest(formattedInput, ctx)
            return response ? response.ingest : null
        },
        updateIngest: async (_, { input }, ctx) => {
            const formattedInput = getFormattedIngest(input, "encode")
            const response = await updateIngestRequest(formattedInput, ctx)
            return response ? response.ingest : null
        },
    },
    ArbitraryObject: () => ObjectScalarType,
}


Appolo query

gql`query ${scope}Ingest($input: PolicyByNameInput){
                policy: ${scope}Ingest(input: $input) {
                    name
                    requiredKeys
                    fieldTransforms {
                        sourceKey
                        operation
                        parameters {
                            preTagField
                            targetGroup
                            substringReplacements
                            groupNamesToTagsMap
                            replacementGroupsMap
                        }
                    }
            }`
  • Вопрос задан
  • 105 просмотров
Решения вопроса 1
Fi1osof
@Fi1osof
JS fullstack developer
У вас ArbitraryObject - scalar, а не объект с описанными полями. На это вам и ругается граф - нельзя в запросе перечислять какие-либо поля для него. То есть нельзя написать запрос типа
query {
   my_query {
     scalar_field {
        ...someFields
     }
   }
}

Можно только
query {
   my_query {
     scalar_field
   }
}
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы