Pular para conteúdo

validation: Biblioteca de Validação (Validação e Filtragem de Entrada) para Lua e nginx-module-lua

Instalação

Se você ainda não configurou a assinatura do repositório RPM, inscreva-se. Depois, você pode prosseguir com os seguintes passos.

CentOS/RHEL 7 ou Amazon Linux 2

yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install lua-resty-validation

CentOS/RHEL 8+, Fedora Linux, Amazon Linux 2023

dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install lua5.1-resty-validation

Para usar esta biblioteca Lua com o NGINX, certifique-se de que o nginx-module-lua está instalado.

Este documento descreve lua-resty-validation v2.7 lançado em 25 de agosto de 2017.


lua-resty-validation é uma biblioteca de validação e filtragem encadeável e extensível para Lua e OpenResty.

Olá Mundo com lua-resty-validation

local validation = require "resty.validation"

local valid, e = validation.number:between(0, 9)(5)  -- valid = true,  e = 5
local valid, e = validation.number:between(0, 9)(50) -- valid = false, e = "between"

-- Validadores podem ser reutilizados
local smallnumber = validation.number:between(0, 9)
local valid, e = smallnumber(5)  -- valid = true,  e = 5
local valid, e = smallnumber(50) -- valid = false, e = "between"

-- Validadores podem fazer filtragem (ou seja, modificar o valor sendo validado)
-- valid = true, s = "HELLO WORLD!"
local valid, s = validation.string.upper "hello world!"

-- Você pode estender a biblioteca de validação com seus próprios validadores e filtros...
validation.validators.capitalize = function(value) 
    return true, value:gsub("^%l", string.upper)
end

-- ... e então usá-la
local valid, e = validation.capitalize "abc" -- valid = true,  e = "Abc"

-- Você também pode validar em grupo muitos valores
local group = validation.new{
    artist = validation.string:minlen(5),
    number = validation.tonumber:equal(10)
}

local valid, fields, errors = group{ artist = "Eddie Vedder", number = "10" }

if valid then
  print("todos os campos do grupo são válidos")
else
  print(fields.artist.name,      fields.artist.error,
        fields.artist.valid,     fields.artist.invalid,
        fields.artist.input,     fields.artist.value,
        fields.artist.validated, fields.artist.unvalidated)
end

-- Você pode até chamar fields para obter uma tabela simples de nome e valor
-- (nesse caso, todos os `nil`s também são removidos)

-- Por padrão, isso retorna apenas os nomes e valores dos campos válidos:
local data = fields()
local data = fields "valid"

-- Para obter apenas os nomes e valores dos campos inválidos, chame:
local data = fields "invalid"

-- Para obter apenas os nomes e valores dos campos validados, chame (se são válidos ou não):
local data = fields "validated"

-- Para obter apenas os nomes e valores dos campos não validados, chame (se são válidos ou não):
local data = fields "unvalidated"

-- Para obter todos, chame:
local data = fields "all"

-- Ou combine:
local data = fields("valid", "invalid")

-- Isso não para aqui. Você também pode querer obter apenas alguns campos pelo nome.
-- Você pode fazer isso chamando (retorna uma tabela):
local data = data{ "artist" }

Validadores e Filtros Integrados

lua-resty-validation vem com vários validadores integrados, e o projeto está aberto a contribuições de mais validadores.

Validadores e Filtros sem Argumentos

Validadores de tipo podem ser usados para validar o tipo do valor validado. Esses validadores são validadores sem argumentos (chame-os com ponto .):

  • null ou ["nil"] (já que nil é uma palavra-chave reservada em Lua)
  • boolean
  • number
  • string
  • table
  • userdata
  • func ou ["function"] (já que function é uma palavra-chave reservada em Lua)
  • callable (seja uma função ou uma tabela com metamétodo __call)
  • thread
  • integer
  • float
  • file (io.type(value) == 'file')

Filtros de conversão de tipo:

  • tostring
  • tonumber
  • tointeger
  • toboolean

Outros filtros:

  • tonil ou tonull
  • abs
  • inf
  • nan
  • finite
  • positive
  • negative
  • lower
  • upper
  • trim
  • ltrim
  • rtrim
  • reverse
  • email
  • optional

Exemplo

local validation = require "resty.validation"
local ok, e = validation.null(nil)
local ok, e = validation.boolean(true)
local ok, e = validation.number(5.2)
local ok, e = validation.string('Hello, World!')
local ok, e = validation.integer(10)
local ok, e = validation.float(math.pi)
local f = assert(io.open('filename.txt', "r"))
local ok, e = validation.file(f)

Validadores e Filtros de Fábrica de Validação

A fábrica de validação consiste em diferentes validadores e filtros usados para validar ou filtrar o valor (chame-os com dois pontos :):

  • type(t), valida que o valor é do tipo t (veja Validadores de Tipo)
  • nil() ou ["null"](), verifica se o tipo do valor é nil
  • boolean(), verifica se o tipo do valor é boolean
  • number(), verifica se o tipo do valor é number
  • string(), verifica se o tipo do valor é string
  • table(), verifica se o tipo do valor é table
  • userdata(), verifica se o tipo do valor é userdata
  • func() ou ["function"](), verifica se o tipo do valor é function
  • callable(), verifica se o valor é chamável (ou seja, uma função ou uma tabela com metamétodo __call)
  • thread(), verifica se o tipo do valor é thread
  • integer(), verifica se o tipo do valor é integer
  • float(), verifica se o tipo do valor é float
  • file(), verifica se o tipo do valor é file (io.type(value) == 'file')
  • abs(), filtra o valor e retorna o valor absoluto (math.abs)
  • inf(), verifica se o valor é inf ou -inf
  • nan(), verifica se o valor é nan
  • finite(), verifica se o valor não é nan, inf ou -inf
  • positive(), valida que o valor é positivo (> 0)
  • negative(), valida que o valor é negativo (< 0)
  • min(min), valida que o valor é pelo menos min (>=)
  • max(max), valida que o valor é no máximo max (<=)
  • between(min[, max = min]), valida que o valor está entre min e max
  • outside(min[, max = min]), valida que o valor não está entre min e max
  • divisible(number), valida que o valor é divisível por number
  • indivisible(number), valida que o valor não é divisível por number
  • len(min[, max = min]), valida que o comprimento do valor é exatamente min ou entre min e max (UTF-8)
  • minlen(min), valida que o comprimento do valor é pelo menos min (UTF-8)
  • maxlen(max), valida que o comprimento do valor é no máximo max (UTF-8)
  • equals(equal) ou equal(equal), valida que o valor é exatamente algo
  • unequals(equal) ou unequal(equal), valida que o valor não é exatamente algo
  • oneof(...), valida que o valor é igual a um dos argumentos fornecidos
  • noneof(...), valida que o valor não é igual a nenhum dos argumentos fornecidos
  • match(pattern[, init]), valida que o valor corresponde (string.match) ao padrão
  • unmatch(pattern[, init]), valida que o valor não corresponde (string.match) ao padrão
  • tostring(), converte o valor para string
  • tonumber([base]), converte o valor para número
  • tointeger(), converte o valor para inteiro
  • toboolean(), converte o valor para booleano (usando not not value)
  • tonil() ou tonull(), converte o valor para nil
  • lower(), converte o valor para minúsculas (suporte a UTF-8 ainda não implementado)
  • upper(), converte o valor para maiúsculas (suporte a UTF-8 ainda não implementado)
  • trim([pattern]), remove espaços em branco (você pode usar um padrão também) da esquerda e da direita
  • ltrim([pattern]), remove espaços em branco (você pode usar um padrão também) da esquerda
  • rtrim([pattern]), remove espaços em branco (você pode usar um padrão também) da direita
  • starts(starts), verifica se a string começa com starts
  • ends(ends), verifica se a string termina com ends
  • reverse, inverte o valor (string ou número) (UTF-8)
  • coalesce(...), se o valor for nil, retorna o primeiro valor não-nil passado como argumento
  • email(), valida que o valor é um endereço de email
  • call(function), valida / filtra o valor contra um validador / filtro inline personalizado
  • optional([default]), para a validação se o valor é uma string vazia "" ou nil e retorna true, e, ou, default ou value

Validadores de Fábrica de Validação Condicional

Para todos os Validadores de Fábrica de Validação, há uma versão condicional que sempre valida como verdadeira, mas onde você pode substituir o valor real dependendo se o validador original validou. Ei, isso é mais fácil de mostrar do que dizer:

local validation = require "resty.validation"

-- ok == true, value == "Sim, o valor é nil"
local ok, value = validation:ifnil(
    "Sim, o valor é nil",
    "Não, você não forneceu um valor nil")(nil)

-- ok == true, value == "Não, você não forneceu um valor nil"
local ok, value = validation:ifnil(
    "Sim, o valor é nil",
    "Não, você não forneceu um valor nil")("non nil")

-- ok == true, value == "Sim, o número está entre 1 e 10"    
local ok, value = validation:ifbetween(1, 10,
    "Sim, o número está entre 1 e 10",
    "Não, o número não está entre 1 e 10")(5)

-- ok == true, value == "Não, o número não está entre 1 e 10"
local ok, value = validation:ifbetween(1, 10,
    "Sim, o número está entre 1 e 10",
    "Não, o número não está entre 1 e 10")(100)

Os últimos 2 argumentos para validadores de fábrica de validação condicional são os valores truthy e falsy. Todos os outros argumentos são passados para o validador de fábrica de validação real.

Validadores de Grupo

lua-resty-validation atualmente suporta alguns validadores pré-definidos:

  • compare(comparison), compara dois campos e define os campos como inválidos ou válidos de acordo com a comparação
  • requisite{ fields }, pelo menos um dos campos requisitados é necessário, mesmo que eles por si mesmos sejam opcionais
  • requisites({ fields }, number), pelo menos number dos campos requisitados são necessários (por padrão, todos eles)
  • call(function), chama uma função de validação de grupo personalizada (ou inline)
local ispassword = validation.trim:minlen(8)
local group = validation.new{
    password1 = ispassword,
    password2 = ispassword
}
group:compare "password1 == password2"
local valid, fields, errors = group{ password1 = "qwerty123", password2 = "qwerty123" }

local optional = validation:optional"".trim
local group = validation.new{
    text = optional,
    html = optional
}
group:requisite{ "text", "html" }
local valid, fields, errors = group{ text = "", html = "" }


local optional = validation:optional ""
local group = validation.new{
    text = optional,
    html = optional
}
group:requisites({ "text", "html" }, 2)
-- ou group:requisites{ "text", "html" }
local valid, fields, errors = group{ text = "", html = "" }


group:call(function(fields)
    if fields.text.value == "hello" then
        fields.text:reject "o texto não pode ser 'hello'"
        fields.html:reject "porque o texto era 'hello', este campo também é invalidado"
    end
end)

Você pode usar operadores relacionais normais do Lua no validador de grupo compare:

  • <
  • >
  • <=
  • >=
  • ==
  • ~=

requisite e requisites verificam se o valor do campo é nil ou "" (string vazia). Com requisite, se todos os campos especificados forem nil ou "", então todos os campos são inválidos (desde que não fossem inválidos por si mesmos), e se pelo menos um dos campos for válido, então todos os campos são válidos. requisites funciona da mesma forma, mas lá você pode definir o número de quantos campos você deseja que tenham um valor que não seja nil e não seja uma string vazia "". Isso fornece validação condicional no sentido de:

  1. Eu tenho (dois ou mais) campos
  2. Todos eles são opcionais
  3. Pelo menos um / número definido de campos deve ser preenchido, mas não me importo qual, desde que haja pelo menos um / número definido de campos preenchidos

Validadores de Parada

Validadores de parada, como optional, são como validadores normais, mas em vez de retornar true ou false como resultado da validação OU como um valor filtrado, você pode retornar validation.stop. Esse valor também pode ser usado dentro de validadores condicionais e em validadores que suportam valores padrão. Aqui está como o validador optional é implementado:

function factory.optional(default)
    return function(value)
        if value == nil or value == "" then
            return validation.stop, default ~= nil and default or value
        end
        return true, value
    end
end

Esses são aproximadamente equivalentes:

-- Ambos retornam: true, "default" (eles param o processamento :minlen(10) em entradas nil e "")
local input = ""
local ok, val = validation.optional:minlen(10)(input)
local ok, val = validation:optional(input):minlen(10)(input)
local ok, val = validation:ifoneof("", nil, validation.stop(input), input):minlen(10)(input)

Filtrando o Valor e Definindo o Valor como nil

A maioria dos validadores, que não estão filtrando o valor, apenas retornam true ou false como resultado. Isso significa que não há como sinalizar resty.validation para realmente definir o valor como nil. Então, há uma solução alternativa, você pode retornar validation.nothing como um valor, e isso mudará o valor para nil, por exemplo, o validador integrado tonil é na verdade implementado assim (pseudo):

function()
    return true, validation.nothing
end

Validadores e Filtros Personalizados (Inline)

Às vezes, você pode ter apenas validadores / filtros únicos que não está usando em outro lugar, ou que você apenas quer fornecer rapidamente um validador / filtro adicional para um caso específico. Para facilitar isso, introduzimos o método de fábrica call com lua-resty-validation 2.4. Aqui está um exemplo:

validation:call(function(value)
    -- agora valide / filtre o valor e retorne os resultados
    -- aqui apenas retornamos false (ou seja, fazendo a validação falhar) 
    return false
end)("Verifique este valor"))

(claro que não precisa ser uma função inline, pois em Lua todas as funções são cidadãos de primeira classe e podem ser passadas como parâmetros)

Extensões de Validador Integradas

Atualmente, lua-resty-validation tem suporte para duas extensões ou plugins que você pode habilitar:

  • resty.validation.ngx
  • resty.validation.tz
  • resty.validation.utf8

Esses são algo que você pode olhar se quiser construir sua própria extensão de validador. Se você fizer isso e achar que seria utilizável para outros também, não se esqueça de enviar sua extensão como um pull-request para inclusão neste projeto, muito obrigado, ;-).

Extensão resty.validation.ngx

Como o nome diz, este conjunto de extensões de validadores requer OpenResty (ou módulo Lua Nginx pelo menos). Para usar esta extensão, tudo que você precisa fazer é:

require "resty.validation.ngx"

Ele irá modificar os adaptadores que fornecerá em resty.validation, e atualmente são:

  • escapeuri
  • unescapeuri
  • base64enc
  • base64dec
  • crc32short
  • crc32long
  • crc32
  • md5

(há tanto versão de fábrica quanto versão sem argumentos dessas)

Há também um correspondedor regex na extensão ngx que usa ngx.re.match, e md5 parametrizado:

  • regex(regex[, options])
  • md5([bin])
Exemplo
require "resty.validation.ngx"
local validation = require "resty.validation"
local valid, value = validation.unescapeuri.crc32("https://github.com/")
local valid, value = validation:unescapeuri():crc32()("https://github.com/")

Extensão resty.validation.tz

Este conjunto de validadores e filtros é baseado na ótima biblioteca luatz de @daurnimator, que é uma biblioteca para manipulação de data e hora. Para usar esta extensão, tudo que você precisa fazer é:

require "resty.validation.tz"

Ele irá modificar os adaptadores que fornecerá em resty.validation, e atualmente são:

  • totimetable
  • totimestamp

(há tanto versão de fábrica quanto versão sem argumentos dessas)

Os filtros totimestamp e totimetable funcionam muito bem com campos de entrada de data e datetime do HTML5. Como o nome diz, totimetable retorna timetable do luatz e totimestamp retorna segundos desde a época unix (1970-01-01) como um número Lua.

Exemplo
require "resty.validation.tz"
local validation = require "resty.validation"
local valid, ts = validation.totimestamp("1990-12-31T23:59:60Z")
local valid, ts = validation.totimestamp("1996-12-19")

Extensão resty.validation.utf8

Este conjunto de validadores e filtros é baseado na ótima biblioteca utf8rewind de Quinten Lansu - uma biblioteca de sistema escrita em C projetada para estender as funções padrão de manipulação de strings com suporte para texto codificado em UTF-8. Ele precisa do meu wrapper FFI do LuaJIT lua-resty-utf8rewind para funcionar. Quando os requisitos mencionados estão instalados, o resto é fácil. Para usar esta extensão, tudo que você precisa fazer é:

require "resty.validation.utf8"

Ele irá modificar os adaptadores que fornecerá em resty.validation, e atualmente são:

  • utf8upper
  • utf8lower
  • utf8title

(há tanto versão de fábrica quanto versão sem argumentos dessas)

Há também alguns validadores / filtros de fábrica:

  • utf8normalize(form)
  • utf8category(category)

O utf8normalize normaliza a entrada UTF-8 para um desses formatos de normalização:

  • C (ou NFC)
  • D (ou NFD)
  • KC (ou NFKC)
  • KD (ou NFKD)

O utf8category verifica se a string de entrada está em uma das seguintes categorias (então, você pode pensar que tem múltiplos validadores integrados para trabalhar com validação de string UTF-8):

  • LETTER_UPPERCASE
  • LETTER_LOWERCASE
  • LETTER_TITLECASE
  • LETTER_MODIFIER
  • CASE_MAPPED
  • LETTER_OTHER
  • LETTER
  • MARK_NON_SPACING
  • MARK_SPACING
  • MARK_ENCLOSING
  • MARK
  • NUMBER_DECIMAL
  • NUMBER_LETTER
  • NUMBER_OTHER
  • NUMBER
  • PUNCTUATION_CONNECTOR
  • PUNCTUATION_DASH
  • PUNCTUATION_OPEN
  • PUNCTUATION_CLOSE
  • PUNCTUATION_INITIAL
  • PUNCTUATION_FINAL
  • PUNCTUATION_OTHER
  • PUNCTUATION
  • SYMBOL_MATH
  • SYMBOL_CURRENCY
  • SYMBOL_MODIFIER
  • SYMBOL_OTHER
  • SYMBOL
  • SEPARATOR_SPACE
  • SEPARATOR_LINE
  • SEPARATOR_PARAGRAPH
  • SEPARATOR
  • CONTROL
  • FORMAT
  • SURROGATE
  • PRIVATE_USE
  • UNASSIGNED
  • COMPATIBILITY
  • ISUPPER
  • ISLOWER
  • ISALPHA
  • ISDIGIT
  • ISALNUM
  • ISPUNCT
  • ISGRAPH
  • ISSPACE
  • ISPRINT
  • ISCNTRL
  • ISXDIGIT
  • ISBLANK
  • IGNORE_GRAPHEME_CLUSTER
Exemplo
require "resty.validation.utf8"
local validation = require "resty.validation"
local valid, ts = validation:utf8category("LETTER_UPPERCASE")("TEST")

Extensão resty.validation.injection

Este conjunto de validadores e filtros é baseado na ótima biblioteca libinjection de Nick Galbreath - um analisador de tokenização SQL / SQLI / XSS. Ele precisa do meu wrapper FFI do LuaJIT lua-resty-injection para funcionar. Quando os requisitos mencionados estão instalados, o resto é fácil. Para usar esta extensão, tudo que você precisa fazer é:

require "resty.validation.injection"

Ele irá modificar os adaptadores que fornecerá em resty.validation, e atualmente são:

  • sqli, retorna false se a injeção SQL foi detectada, caso contrário retorna true
  • xss, retorna false se a injeção de Cross-Site Scripting foi detectada, caso contrário retorna true
Exemplo
require "resty.validation.injection"
local validation = require "resty.validation"
local valid, ts = validation.sqli("test'; DELETE FROM users;")
local valid, ts = validation.xss("test <script>alert('XSS');</script>")

API

Não vou entrar em detalhes sobre todos os diferentes validadores e filtros que existem, pois todos seguem a mesma lógica, mas vou mostrar algumas maneiras gerais de como isso funciona.

validation._VERSION

Este campo contém uma versão da biblioteca de validação, por exemplo, seu valor pode ser "2.5" para a versão 2.5 desta biblioteca.

validação booleana, valor/erro...

Esse ... significa a cadeia de validação. Isso é usado para definir uma única cadeia de validadores. Não há limite para o comprimento da cadeia. Ele sempre retornará um booleano (se a validação é válida ou não). O segundo valor de retorno será o nome do filtro que não retornou true como resultado da validação, ou o valor filtrado.

local v = require "resty.validation"

-- O abaixo significa, criar um validador que verifica se a entrada é:
-- 1. string
-- Se for, então remova os espaços em branco do início e do fim da string:
-- 2. trim
-- Então verifique se o comprimento da string filtrada é pelo menos 5 caracteres (UTF-8):
-- 3. minlen(5)
-- E se tudo ainda estiver ok, converta essa string para maiúsculas
-- (UTF-8 ainda não é suportado em maiúsculas):
-- 4. upper
local myvalidator = v.string.trim:minlen(5).upper

-- Este exemplo retornará false e "minlen"
local valid, value = myvalidator(" \n\t a \t\n ")

-- Este exemplo retornará true e "ABCDE"
local valid, value = myvalidator(" \n\t abcde \t\n ")

Sempre que o validador falhar e retornar false, você não deve usar o valor retornado para outros propósitos além do relatório de erros. Portanto, a cadeia funciona assim. O lua-resty-validation não tentará fazer nada se você especificar cadeias que nunca serão usadas, como:

local v = require "resty.validation"
-- O valor de entrada nunca pode ser tanto string quanto number ao mesmo tempo:
local myvalidator = v.string.number:max(3)
-- Mas você poderia escrever isso assim
-- (pegar a entrada como uma string, tentar convertê-la para número e verificar se é no máximo 3):
local myvalidator = v.string.tonumber:max(3)

Como você vê, esta é uma maneira de definir validadores reutilizáveis únicos. Você pode, por exemplo, pré-definir seu conjunto de cadeias de validadores únicos básicos e armazená-las em seu próprio módulo do qual você pode reutilizar a mesma lógica de validação em diferentes partes de sua aplicação. É uma boa ideia começar definindo validadores únicos reutilizáveis e depois reutilizá-los em validadores de grupo.

Por exemplo, digamos que você tenha um módulo chamado validators:

local v = require "resty.validation"
return {
    nick     = v.string.trim:minlen(2),
    email    = v.string.trim.email,
    password = v.string.trim:minlen(8)
}

E agora você tem a função register em algum lugar em sua aplicação:

local validate = require "validators"
local function register(nick, email, password)
    local vn, nick     = validate.nick(nick)
    local ve, email    = validate.email(email)
    local vp, password = validate.password(password)
    if vn and ve and vp then
        -- a entrada é válida, faça algo com nick, email e password
    else
        -- a entrada é inválida, nick, email e password contêm os motivos de erro
    end
end

Isso rapidamente fica um pouco sujo, e é por isso que temos validadores de grupo.

validação.table.new([tabela de validadores])

Esta função é onde a validação em grupo começa. Digamos que você tenha um formulário de registro que pede seu nick, email (o mesmo duas vezes) e senha (o mesmo duas vezes).

Vamos reutilizar os validadores únicos, definidos no módulo validators:

local v = require "resty.validation"
return {
    nick     = v.string.trim:minlen(2),
    email    = v.string.trim.email,
    password = v.string.trim:minlen(8)
}

Agora, vamos criar o validador de grupo reutilizável no módulo forms:

local v        = require "resty.validation"
local validate = require "validators"

-- Primeiro, criamos validadores únicos para cada campo do formulário
local register = v.new{
    nick      = validate.nick,
    email     = validate.email,
    email2    = validate.email,
    password  = validate.password,
    password2 = validate.password
}

-- Em seguida, criamos validadores de grupo para email e senha:
register:compare "email    == email2"
register:compare "password == password2"

-- E finalmente, retornamos deste módulo de formulários

return {
    register = register
}

Agora, em algum lugar em sua aplicação você tem esta função register:

local forms = require "forms"
local function register(data)
    local valid, fields, errors = forms.register(data)
    if valid then
        -- a entrada é válida, faça algo com os campos
    else
        -- a entrada é inválida, faça algo com os campos e erros
    end
end

-- E você pode chamá-la assim:

register{
    nick      = "test",
    email     = "[email protected]",
    email2    = "[email protected]",
    password  = "qwerty123",
    password2 = "qwerty123"
}

A grande coisa sobre validadores de grupo é que você pode codificar em JSON a tabela de campos e erros e retorná-la ao cliente. Isso pode ser útil ao construir uma aplicação de página única e você precisa relatar erros do lado do servidor ao cliente. No exemplo acima, a variável fields parecerá assim (valid seria verdadeiro, e errors seria nil):

{
    nick = {
        unvalidated = false,
        value = "test",
        input = "test",
        name = "nick",
        valid = true,
        invalid = false,
        validated = true
    },
    email = {
        unvalidated = false,
        value = "[email protected]",
        input = "[email protected]",
        name = "email",
        valid = true,
        invalid = false,
        validated = true
    },
    email2 = {
        unvalidated = false,
        value = "[email protected]",
        input = "[email protected]",
        name = "email2",
        valid = true,
        invalid = false,
        validated = true
    },
    password = {
        unvalidated = false,
        value = "qwerty123",
        input = "qwerty123",
        name = "password",
        valid = true,
        invalid = false,
        validated = true
    },
    password2 = {
        unvalidated = false,
        value = "qwerty123",
        input = "qwerty123",
        name = "password2",
        valid = true,
        invalid = false,
        validated = true
    }
}

Isso é ótimo para processamento adicional e envio dos campos como JSON codificado de volta para a aplicação Javascript do lado do cliente, mas geralmente essa é uma construção muito pesada para ser enviada para a camada de backend. Para obter uma tabela simples de chave-valor, podemos chamar esta tabela de campos:

local data = fields()

A variável data agora conterá:

{
    nick = "test",
    email = "[email protected]",
    email2 = "[email protected]",
    password = "qwerty123",
    password2 = "qwerty123"
}

Agora isso é algo que você pode enviar, por exemplo, no Redis ou em qualquer camada de banco de dados (abstração) que você tenha. Mas, bem, isso não para aqui, se digamos que sua camada de banco de dados está apenas interessada em nick, email e password (por exemplo, removendo esses duplicados), você pode até chamar a tabela data:

local realdata = data("nick", "email", "password")

O realdata agora conterá:

{
    nick = "test",
    email = "[email protected]",
    password = "qwerty123"
}

field:accept(value)

Para o campo, você pode chamar accept que faz isso:

self.error = nil
self.value = value
self.valid = true
self.invalid = false
self.validated = true
self.unvalidated = false

field:reject(error)

Para o campo, você pode chamar reject que faz isso:

self.error = error
self.valid = false
self.invalid = true
self.validated = true
self.unvalidated = false

string field:state(invalid, valid, unvalidated)

Chamar state no campo é ótimo ao incorporar resultados de validação dentro de, digamos, um template HTML, como lua-resty-template. Aqui está um exemplo usando lua-resty-template:

<form method="post">
    <input class="{{ form.email:state('invalid', 'valid') }}"
            name="email"
            type="text"
            placeholder="Email"
            value="{{ form.email.input }}">
    <button type="submit">Junte-se</button>
</form>

Assim, dependendo do estado do campo de email, isso adicionará uma classe ao elemento de entrada (por exemplo, tornando a borda da entrada vermelha ou verde, por exemplo). Não nos importamos com o estado não validado (por exemplo, quando o usuário carregou a página e o formulário pela primeira vez).

Mudanças

As mudanças de cada versão deste módulo são registradas no arquivo Changes.md.

Veja Também

GitHub

Você pode encontrar dicas de configuração adicionais e documentação para este módulo no repositório GitHub para nginx-module-validation.