Проверить тело запроса отдельно от запроса в целом - PullRequest
0 голосов
/ 28 мая 2020

У меня вопрос по проверке запроса PUT. Тело запроса - это массив объектов. Я хочу, чтобы запрос был успешным, если тело содержит массив, по крайней мере, длиной один, но мне также нужно выполнить отдельную проверку каждого объекта в массиве и передать ее обратно в ответ. Итак, мое тело вставки будет:

[1, 2, {id: "thirdObject"}]

Ответ должен быть 200, даже если первые два элемента даже не являются объектами. Запрос просто должен быть успешным, если в теле передается массив длиной 1. Ответ должен быть примерно таким:

[{id: firstObject, status: 400, error: should be object}, {id: secondObject, status: 400, error: should be object}, { id: thirdObject, status: 204 }]

В настоящее время я проверяю тело как таковое с помощью свободной схемы:

body: S.array().items(myObjectSchema) .minItems(1)

Результатом будет 400, если какой-либо из элементов в теле не соответствует myObjectSchema. Интересно, есть ли у вас идеи, как этого добиться?

Ответы [ 2 ]

1 голос
/ 28 мая 2020

Проверка не сообщает вам, успешна ли схема (например, { id: thirdObject, status: 204 }), поэтому вам нужно управлять ею самостоятельно.

Для этого вам необходимо создать обработчик ошибок для чтения ошибка проверки и слияние с телом запроса:

const fastify = require('fastify')()
const S = require('fluent-schema')

fastify.put('/', {
  handler: () => { /** this will never executed if the schema validation fail */ },
  schema: {
    body: S.array().items(S.object()).minItems(1)
  }
})

const errorHandler = (error, request, reply) => {
  const { validation, validationContext } = error

  // check if we have a validation error
  if (validation) {
    // here the validation error
    console.log(validation)

    // here the body
    console.log(request.body)

    reply.send(validation)
  } else {
    reply.send(error)
  }
}

fastify.setErrorHandler(errorHandler)

fastify.inject({
  method: 'PUT',
  url: '/',
  payload: [1, 2, { id: 'thirdObject' }]
}, (_, res) => {
  console.log(res.json())
})

Будет записано:

[
  {
    keyword: 'type',
    dataPath: '[0]',
    schemaPath: '#/items/type',
    params: { type: 'object' },
    message: 'should be object'
  },
  {
    keyword: 'type',
    dataPath: '[1]',
    schemaPath: '#/items/type',
    params: { type: 'object' },
    message: 'should be object'
  }
]

[ 1, 2, { id: 'thirdObject' } ]

Как видите, благодаря validation[].dataPath вы можете понять, какие элементы массив тела недействителен и объедините данные, чтобы вернуть вашу информацию.

Учтите, что обработчик не будет выполняться в этом сценарии. Если вам нужно выполнить его независимо от проверки, вы должны выполнить задание проверки в ловушке preHandler и избежать проверок проверки схемы по умолчанию (поскольку она блокирует)


edit

const fastify = require('fastify')()
const S = require('fluent-schema')

let bodyValidator
fastify.decorateRequest('hasError', function () {
  if (!bodyValidator) {
    bodyValidator = fastify.schemaCompiler(S.array().items(S.object()).minItems(1).valueOf())
  }

  const valid = bodyValidator(this.body)
  if (!valid) {
    return bodyValidator.errors
  }
  return true
})

fastify.addHook('preHandler', (request, reply, done) => {
  const errors = request.hasError()
  if (errors) {
    console.log(errors)
    // show the same errors as before
    // you can merge here or set request.errors = errors to let the handler read them
    reply.send('here merge errors and request.body')
    return
  }

  done() // needed to continue if you don't reply.send
})

fastify.put('/', { schema: { body: S.array() } }, (req, reply) => {
  console.log('handler')
  reply.send('handler')
})

fastify.inject({
  method: 'PUT',
  url: '/',
  payload: [1, 2, { id: 'thirdObject' }]
}, (_, res) => {
  console.log(res.json())
})
0 голосов
/ 28 мая 2020

Я не знаю синтаксис схемы, который вы используете, но использую черновик 7 схемы JSON (https://json-schema.org/specification-links.html, а также см. https://json-schema.org/understanding-json-schema для некоторых справочный материал), вы можете:

{
  "type": "array",
  "minItems": 1
}

Если вы хотите убедиться, что хотя бы один , но не обязательно все элементы соответствуют вашему типу объекта, тогда добавьте ключевое слово "содержит":

{
  ...,
  "contains": ... reference to your object schema here
}
...