npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

mock-totvs-builder

v1.7.0

Published

API desenvolvida para simular o BackEnd, provendo serviços para acessar e manipular Entidades. Ela já implementa os métodos padrões de CRUD (Create, Update e Delete). E para busca dos dados, suporta paginação, ordenação (crescente/decrescente), fields e

Downloads

28

Readme

MOCK TOTVS BUILDER

API desenvolvida para simular o BackEnd, provendo serviços para acessar e manipular Entidades. Ela já implementa os métodos padrões de CRUD (Create, Update e Delete). E para busca dos dados, suporta paginação, ordenação (crescente/decrescente), fields e pesquisa por todos os campos retornados.

Entidade

Representa a informação que será retornada pelo BackEnd, podendo ser um Cadastros (Cliente, Fornecedor, Nota Fiscal) ou mesmo um conjunto de dados (Total de Vendas por Cliente, Informações para montagem de um Gráfico, etc).

Configurando Entidades

Para cada entidade, deverá existir um arquivo de configuração no formato "JSON" que deverá ser salvo na pasta "data" do projeto.

Parâmetros do arquivo de configuração |Parâmetro|Obrig?|Descrição|Exemplo| |--|--|--|--| |entityName(string)|Sim|Nome da entidade, que será utilizado para roteamento.Observação: O nome deve ser único, isto é, não deve existir outra entidade com o mesmo nome.|"customer"| |entityLabel(string)|Não|Descrição da entidade, que será apresentada nas mensagens de erro.Quando não informado será utilizado entityName.|"Cliente"| |keys(array)|Sim|Lista de atributos que fazem parte da chave única da entidade.Quando a chave for composta, os atributos devem estar na ordem esperada.|Ex1 (chave simples):["code"]Ex2 (chave composta):["company","id"]| |keysSeparator(string)|Não|Caracter que será utilizado para concatenar as chaves da entidade durante a busca de dados (get, update, delete), quando ela utilizar chave composta. O caracter deve corresponder ao que já é utilizado atualmente pelo FrontEnd para busca de dados. Por exemplo, para buscar o registro o FrontEnd dispara a requisição: /customer/1\|3\|4, desta forma, o caracter utilizado para separar as chaves foi o pipe ("|"), portanto este caracter deve ser utilizado neste parâmetro.Se não for informado, será utilizado o caracter ponto-e-vírgula (";") |Ex1:";"Ex2:"\|"| |mainPath(string)|Não|Path principal para acesso a entidade. Caso não seja informado, será considerado: "/" + entityName|Ex1:"/customer"Ex2:"/api/cdp/v1/customer"| |customSearchFields(object)|Não|Por padrão, quando é informado um QueryParam com o nome de um atributo da entidade, os dados serão filtrados por este atributo considerando o valor do QueryParam (ver detalhes no tópico Busca Avançada - Filtro (Simples)).Quando for necessário filtrar por um atributo, mas o nome do QueryParam é diferente, é possível fazer a relação de QueryParam x Atributo através deste parâmetro. Por exemplo, é realizada a requisição: "GET /customer?search=Roberto" e os registros devem ser filtrados por "shortName" considerando o valor do QueryParam "search", neste caso basta informar {"search": "shortName"}.|{"initialName": "name", "finalName": "name", "search": "shortName"}| |base64Key(logical)|Não|Indica se a chave da entidade é enviada em Base64 nas requisições de GET, PUT e DELETE. Caso afirmativo, a chave recebida será convertida (base64 decode) antes de realizar a busca da entidade. Se não informado, será considerado como false.|falseOUtrue| |children(array)|Não|Lista de filhos da entidade. Utilizado para quando a entidade possui filhos diretos alinhados (que fazem parte da estrutura da entidade).Para mais detalhes e configuração, verificar o tópico: Configurando Filhos da Entidade.|[{"entityName": "contacts", "entityLabel": "Contato", "keys": ["seq"]},{"entityName": "bankAccount", "base64Key": true, "keys": ["bank", "account"]}]| |customRoutes(array)|Não|Lista de Rotas customizadas. Utilizado para quando as rotas padrões (ver tópico: Rotas Pré-definidas) não atendem.Para configurar as rotas, verificar o tópico: Configurando Rotas Customizadas.|[{"name": "nextId", "method": "GET", "path": "/nextId", "database": "db_nextId"},{"name": "block", "method": "POST", "path": "/:idParam/block", "database": "db_block"}]| |customValidation(array)|Não|Lista de Validações customizadas. Utilizado para simular erros/validações executadas pelo BackEnd.Para configurar as validações, verificar o tópico: Configurando Validações Customizadas.|[{"name": "vld_block","method": ["DELETE"],"from": ["payload","database"],"field": ["status"],"operation": "=","value": 3,"msgError": "Cliente está Bloqueado !"}]| |database(array)|Sim|Registros da Entidade, contendo a entidade completa, com todos os atributos necessários.|[{"company": 10, "code": 1, "shortName": "João", "name": "Joãozinho Maria da Silva" },{"company": 10, "code": 2, "shortName": "Maria", "name": "Maria Barbosa"}]| |queryCustomInf(object)|Não|A Rota Pré-definida de query sempre irá retorna um objeto JSON no formato TotvsResponse (atributos: total, hasNext e items). Caso seja necessário devolver atributos adicionais, é possível envia-los através deste parâmetro.|{"totalGeral": 300, "hasViewPermission": true}|

Exemplo da configuração de uma Entidade

Arquivo: data/customer.json

{
	"entityName": "customer",
	"entityLabel": "Cliente",
	"keys": [ "code" ],
	"database": [
		{
			"code": 1,
			"shortName": "João",
			"name": "Joãozinho da Silva",
			"country": "BRA",
			"status": 2
		},
		{
			"code": 2,
			"shortName": "Maria",
			"name": "Maria Barbosa",
			"country": "BRA",
			"status": 3
		}
	]
}

Rotas Pré-definidas

Segue abaixo a lista de Rotas Pré-definidas para manipulação das Entidades. |Name|Método|Descrição|Exemplo| |--|--|--|--| |query|GET|Retorna todos os registros da entidade, respeitando os parâmetros definidos como Busca Avançada. Veja detalhes no tópico Busca Avançada.O retorno será um objeto JSON no formato TotvsResponse (atributos: total, hasNext e items), acrescido dos atributos adicionais, caso seja informado no parâmetro queryCustomInf da configuração principal da entidade. O resultado da busca estará disponível no atributo "items".|GET /customer| |get|GET|Retorna um registro específico. Para isto, deve ser enviado um PathParam com o valor da chave da entidade. Se a chave for composta, utilizar o caracter informado no parâmetro keysSeparator da entidade, para separar os valores (ex: 10;5). Caso o registro não exista, será retornada uma mensagem de erro.|GET /customer/7| |create|POST|Cria um novo registro. Os dados da entidade devem ser enviados no Payload. Caso já exista um registro com a chave da entidade, será retornada uma mensagem de erro.|POST /customerPayload:{"code": 2, "shortName": "Maria", "name": "Maria Barbosa"}| |update|PUT|Altera um registro específico. Para isto, deve ser enviado um PathParam com o valor da chave da entidade. Se a chave for composta, utilizar o caracter informado no parâmetro keysSeparator da entidade, para separar os valores (ex: 10;5). E, no Payload os dados que devem ser alterados. Caso o registro não exista, será retornada uma mensagem de erro.|PUT /customer/2Payload:{"name": "Maria Barbosa da Silva"}| |delete|DELETE|Elimina um registro específico. Para isto, deve ser enviado um PathParam com o valor da chave da entidade. Se a chave for composta, utilizar o caracter informado no parâmetro keysSeparator da entidade, para separar os valores (ex: 10;5). Caso o registro não exista, será retornada uma mensagem de erro.|DELETE /customer/10|

Observações:

  • A busca (get/query) será realizada sobre os Registros existentes no parâmetro "database" do arquivo de configuração de entidade;
  • Sempre que a entidade for manipulada (inclusão/alteração/exclusão), as alterações serão salvas no parâmetro "database" do arquivo de configuração de entidade;
  • Todas as buscas realizadas não são case sensitive.

Busca Avançada

Ao fazer uma requisição, permite enviar QueryParams pré-definidos para filtrar ou manipular o retorno das informações, conforme tabela abaixo:

|Funcionalidade|Descrição|Exemplo| |--|--|--| |Paginação(pageSize, page)|Realiza o controle de Paginação, retornando as páginas conforme solicitado. Caso não sejam enviados, serão considerados "page = 1" e "pageSize = 20".|/customer?page=1&pageSize=10| |Filtro (Simples)(atributo=valor)|Possibilita realizar filtros utilizando todos os atributos existentes na entidade. O valor poderá ser uma informação qualquer, que seja do mesmo tipo de dado do atributo. Caso o tipo de dado seja string, a busca não será pelo valor exato, ela irá considerar que o atributo contenha este valor.|/customer?name=João| |Filtro (Range)(atributo=valIni;ValFim)|Realiza o filtro considerando uma faixa. Neste caso, os valores inicial e final, devem ser enviados com o separador ";".|/customer?code=2;5| |Filtro (Lista - Tipo 1)(atributo=val1,val2,valN)|Realiza o filtro considerando uma lista. Neste caso, os valores devem ser enviados com o separador ",".|/customer?country=BRA,USA,ARG| |Filtro (Lista - Tipo 2)(atributo=val1&atributo=valN)|Realiza o filtro considerando uma lista. Neste caso, os valores devem ser enviados repetindo-se o QueryParam para cada item da lista.|/customer?country=BRA&country=USA&country=ARG| |Seleção de Atributos(fields)|Permite indicar quais atributos da entidade devem ser retornados. Para isto, deve ser enviado o QueryParam "fields" com a lista de atributos. Caso não seja enviado, retorna todos os atributos da entidade.|/customer?fields=code,name| |Ordenação(order)|Permite indicar um atributo para realizar a ordenação dos dados retornados. Para isto, deve ser enviado o QueryParam "order" com o nome do atributo. Utilizar o caracter '-' na frente do atributo para indicar que a ordenação seja descendente. Caso não seja enviado, os dados serão retornados na ordem em que estiver no arquivo de configuração da entidade.|/customer?order=name|

Configurando Filhos da Entidade

Esta configuração é utilizada para quando a entidade possui filhos e eles são alinhados, fazendo parte da estrutura da entidade, isto é, a lista de filhos esta dentro da entidade em um atributo do tipo array. Por exemplo, a entidade customer possui um atributo array chamado contacts e nele está a lista de contatos, conforme exemplo abaixo:

{
	"code": 1,
	"shortName": "João",
	"contacts": [
		{
			"seq": 1,
			"name": "Joaquim"
		}
	]
}

Ao realizar esta configuração, serão criadas automaticamente as rotas para busca e manipulação dos filhos da entidade. As rotas e regras utilizadas, serão as mesmas utilizadas nas rotas pré-definidas da entidade (ver tópico: Rotas Pré-definidas), sendo que, o Path seguirá o padrão conforme abaixo: |Rota|Path| |--|--| |query|/entidade/:idEntidade/filho| |get|/entidade/:idEntidade/filho/:idFilho| |create|/entidade/:idEntidade/filho| |update|/entidade/:idEntidade/filho/:idFilho| |delete|/entidade/:idEntidade/filho/:idFilho|

Para realizar a configuração dos filhos, basta incluir o parâmetro "children" no arquivo de configuração da Entidade e incluir a lista de filhos. Cada filho, deve respeitar a configuração conforme tabela abaixo: |Parâmetro|Obrig?|Descrição|Exemplo| |--|--|--|--| |entityName(string)|Sim|Nome do filho, que será utilizado para roteamento.Observação: O nome deve ser único, isto é, não deve existir outro filho da mesma entidade com o mesmo nome.|"contact"| |entityLabel(string)|Não|Descrição do filho, que será apresentada nas mensagens de erro.Quando não informado, será utilizado entityName.|"Contato"| |property(string)|Não|Nome do atributo da entidade que possui a lista do filho.Quando não informado, será utilizado entityName.|"contacts"| |keys(array)|Sim|Lista de atributos que fazem parte da chave única do filho (desconsiderando a chave da entidade).Quando a chave for composta, os atributos devem estar na ordem esperada.|Ex1 (chave simples):["seq"]Ex2 (chave composta):["bank","account"]| |keysSeparator(string)|Não|Caracter que será utilizado para concatenar as chaves do filho durante a busca de dados (get, update, delete), quando ele utilizar chave composta. O caracter deve corresponder ao que já é utilizado atualmente pelo FrontEnd para busca de dados. Por exemplo, para buscar o registro o FrontEnd dispara a requisição: /customer/1/bankAccount/001\|31232, desta forma, o caracter utilizado para separar as chaves foi o pipe ("|"), portanto este caracter deve ser utilizado neste parâmetro.Se não for informado, será utilizado o caracter ponto-e-vírgula (";") |Ex1:";"Ex2:"\|"| |base64Key(logical)|Não|Indica se a chave do filho é enviada em Base64 nas requisições de GET, PUT e DELETE. Caso afirmativo, a chave recebida será convertida (base64 decode) antes de realizar a busca da entidade. Se não informado, será considerado como false.|falseOUtrue|

Exemplo Configuração:

Arquivo: data/customer.json

{
	"entityName": "customer",
	"entityLabel": "Cliente",
	"keys": [ "code" ],
	"children": [
		{
			"entityName": "contact",
			"entityLabel": "Contato",
			"property": "contacts",
			"keys": [ "seq" ]
		},
		{
			"entityName": "bankAccount",
			"base64Key": true,
			"keys": [ "bank", "account" ]
		}
	]
}

Configurando Rotas Customizadas

Quando as rotas padrões pré-definidas não atendem, é possível configurar novas rotas. Para isto, basta incluir o parâmetro "customRoutes" no arquivo de configuração da Entidade e incluir a lista de rotas. Cada rota, deve respeitar a configuração conforme tabela abaixo: |Parâmetro|Obrig?|Descrição|Exemplos| |--|--|--|--| |name(string)|Sim|Um nome qualquer para identificar a rota. Será apresentado no Log quando realizada uma requisição para ela.Observação: O nome deve ser único, isto é, não deve existir outra rota (Pré-definida ou Customizada) com o mesmo nome.|"nextId"| |method(string)|Sim|Método da Requisição. Podendo ser:- GET: Utilizado para retornar alguma informação (ex: Próximo ID, Valores totais de uma pesquisa, etc).- PUT ou POST: Utilizado para executar alguma ação ou enviar alguma informação (Bloquear um cliente, Disparar um relatório, Enviar dados para duplicar um cliente, etc).- DELETE: Utilizado para executar um delete customizado (fora do padrão).Observações: - Independente do método, serão aplicadas as mesmas regras de pesquisa de Busca Avançada (ver tópico Rotas Pré-definidas - Busca Avançada), desta forma, terá o controle de Paginação, Ordenação, Filtro, etc;- A pesquisa será realizada sobre a lista informada no parâmetro "database" da rota.|"GET"OU"PUT"OU"POST"OU"DELETE"| |path(string)|Sim|URL que será utilizado na Requisição. É a informação que virá após o mainPath da entidade. Por exemplo, na URL "/customer/nextId" deve ser informado "/nextId".Também é possível indicar parâmetros na URL, utilizando ":" + "nome-parâmetro" (ex: "/:idCust/block"). Ele será utilizado para filtrar a lista informada no parâmetro "database" da rota. Para isto, é necessário que exista um atributo na lista com o mesmo nome do parâmetro. Por exemplo, para a URL "/:idCust/block" deve existir um atributo chamado "idCust" na lista database da rota. Desta forma, é possível configurar retornos diferentes conforme o parâmetro enviado (ex: Se o cliente for "1" retorna Bloqueio OK, se o cliente for "3", retornar um erro).|Ex1:"/nextId"Ex2:"/:idCust/block"| |savePayload(logical)|Não|Indica se as informações enviadas no Payload das requisições de POST, devem ser salvas no database da rota. Se não informado, será considerado como false.|falseOUtrue| |script(string)|Não|Parâmetro utilizado para informar um programa desenvolvido em NodeJS, que será executado ao receber a requisição na rota. Desta forma é possível programar qualquer comportamento, ou até mesmo realizar algum cálculo com base nos dados.Ver detalhes da configuração no tópico: Configurando Script de Rota.|"customer.js"| |fileParam(object)|Não|Parâmetro utilizado quando a rota é destinada a receber arquivos via Upload, ou realizar o Download de arquivos a partir do Backend.Ver detalhes da configuração no tópico: Configurando Rota para Tratamento de Arquivo.|{"fileName": "#file#_#today#", "directory": "uploads/"}| |responseType(string)|Não|Tipo do Response que será retornado. Podendo ser:- object: Retorna um objeto JSON. Se a pesquisa resultar em mais de um registro, será considerado somente o primeiro.- array: Retorna um objeto JSON no formato TotvsResponse (atributos: total, hasNext e items), sendo que o resultado estará disponível no atributo "items".- file: Utilizado para indicar que a rota irá retornar um arquivo. Ver detalhes no tópico: Configurando Rota para Tratamento de Arquivo.Observações:- Caso não seja informado, será considerado "object";- Quando o tipo for "object", será possível customizar o retorno (ver tópico: Customizando o Response).|"object"OU"array"OU"file"| |queryCustomInf(object)|Não|Atributos adicionais que serão devolvidos quando o parâmetro responseType for igual a array.|{ "totalGeral": 300, "hasViewPermission": true }| |database(string)|Não|Nome da Lista que contém os dados a serem pesquisados ou atualizados. Neste parâmetro pode ser informado o conteúdo "database", para utilizar o database padrão da entidade, ou o nome de um database específico, neste caso, este database deverá ser definida como um novo parâmetro dentro do arquivo de configuração da entidade. Por exemplo, se for informado "db_block", no arquivo de configuração deverá existir um parâmetro com o seguinte nome e formato:"db_block": [ {object1}, {object2}, {objectN} ]Observação: Caso não seja informado, a rota não irá retornar dados em uma pesquisa, e não irá salvar as informações em uma atualização.|Ex1:"db_block"Ex2:"database"|

Configurando Script de Rota

É possível configurar uma Rota Customizada informando um programa desenvolvido em NodeJS, que será executado toda vez que a rota receber uma requisição. Este programa deve ser salvo na pasta "data" do projeto, e o seu nome, informado no parâmetro script da rota. Segue abaixo os tratamento conforme o método da rota: Rotas com método GET:

  • O programa deverá ter uma função chamada "get";
  • Esta função irá receber os seguintes parâmetros:

|Parâmetro|Descrição| |--|--| |paramPath(object)|Objeto com os parâmetros de Path da Requisição. Por exemplo, se o path da rota for "/:idCust/block", o conteúdo enviado na Requisição pode ser acessado da seguinte forma: paramPath.idCust.| |queryParam(object)|Objeto com os parâmetros de Query enviados na Requisição. Por exemplo, se for realizada a requisição /customer?search=Roberto, o conteúdo pode ser acessado da seguinte forma: queryParam.search.| |database(array)|Lista de dados que foram configurados no parâmetro database da rota.|

  • A função poderá retornar um objeto com os seguintes parâmetros:

|Parâmetro|Descrição| |--|--| |statusCode(number)|Código de Status a ser retornado na Requisição (ex: 200, 404, 500). Se não for informado, será retornado 200.| |response(object)|Objeto de Response, retornado na Requisição. Se não for informado, será retornado um objeto vazio.|

Rotas com método PUT, POST ou DELETE:

  • O programa deverá ter uma função chamada "put", "post" ou "delete";

|Parâmetro|Descrição| |--|--| |paramPath(object)|Objeto com os parâmetros de Path da Requisição. Por exemplo, se o path da rota for "/:idCust/block", o conteúdo enviado na Requisição pode ser acessado da seguinte forma: paramPath.idCust.| |queryParam(object)|Objeto com os parâmetros de Query enviados na Requisição. Por exemplo, se for realizada a requisição /customer?search=Roberto, o conteúdo pode ser acessado da seguinte forma: queryParam.search.| |payload(object)|Objeto com as informações enviadas no Payload da Requisição.| |database(array)|Lista de dados que foram configurados no parâmetro database da rota.|

  • A função poderá retornar um objeto com os seguintes parâmetros:

|Parâmetro|Descrição| |--|--| |statusCode(number)|Código de Status a ser retornado na Requisição (ex: 200, 404, 500). Se não for informado, será retornado 200.| |response(object)|Objeto de Response, retornado na Requisição. Se não for informado, será retornado um objeto vazio.| |database(array)|Lista de Dados que serão salvas no parâmetro database da rota. Por exemplo, na rota foi configurado um database que possui um registro de cliente. A função de "post" do script irá receber este database, se a função incluir um novo registro nele, e ele for retornado, este novo registro será salvo. Se este campo não for informado, as informações alteradas pela função não serão salvas.|

Configurando Rota para Tratamento de Arquivo

É possível configurar uma Rota Customizada para receber arquivos via Upload ou realizar o Download de arquivos a partir do Backend. Para isto, basta seguir as orientações abaixo conforme cada tipo: Upload de Arquivos:

  • O parâmetro "method" da rota deverá ser igual a "PUT" ou "POST";
  • Deverá ser incluído o parâmetro "fileParam" na rota (detalhe na tabela abaixo), para configuração do nome e diretório de destino onde os arquivos serão salvos;
  • Os detalhes dos arquivos recebidos, serão salvos no parâmetro "database" configurado na rota, caso ele seja informado. Portanto neste caso, se for informado, o ideal é ter um database específico;
  • Os detalhes dos arquivos também serão retornados no response da requisição, no formato JSON, portanto o "responseType" não precisa ser informado, ou deve ser igual a "object".

Download de Arquivos:

  • O parâmetro "method" da rota deverá ser igual a "GET", "PUT" ou "POST";
  • Deverá ser incluído o parâmetro "fileParam" na rota (detalhe na tabela abaixo), para configuração do nome e diretório onde os arquivos estarão fisicamente;
  • Se o arquivo não existir no diretório configurado no momento da requisição, será retornado um erro 404;
  • O parâmetro "database" da rota não é utilizado. Portanto ele não deve ser informado;
  • O parâmetro "responseType" da rota deverá ser igual "file".

O parâmetro "fileParam" é um objeto JSON, que possui os parâmetros descritos na tabela abaixo:

|Parâmetro|Obrig?|Descrição|Exemplos| |--|--|--|--| |fileName(string)|Não (upload)Sim (download)|Para Rotas de Upload de Arquivos: Através deste parâmetro, é possível determinar o nome do arquivo recebido, isto é, qual será o nome do arquivo físico salvo no diretório parametrizado (directory). O ideal é não informar a extensão do arquivo, desta forma, será assumida a extensão do arquivo original enviado no Upload. Se este parâmetro não for informado, será considerado o nome original do arquivo.Para Rotas de Download de Arquivos: Neste parâmetro deve ser informado o nome do arquivo existente no diretório parametrizado (directory).O nome do arquivo pode conter caracteres fixos e/ou variáveis. Por exemplo, informando "#file#-#today#", o nome será igual ao nome original (upload), seguindo de um traço e a data de hoje.As variáveis disponíveis são:- #file#: Nome original do arquivo (somente disponível para upload).- #today#: Data atual, no formato: AAAA-MM-AA.- #now#: Momento atual em milissegundos.- Um parâmetro da URL: Se na rota customizada foi informado um parâmetro (ex: :idArq), este parâmetro pode ser utilizado para determinar o nome arquivo. Para isto, basta informar o nome do parâmetro entre "#" (ex: #idArq#).|Ex1:"#today#-#file#"Ex2:"#file#_#now#"Ex3:"arq_id-#idCust#"Ex4:"layout-200.txt"| |directory(string)|Sim|Para Rotas de Upload de Arquivos: Deve ser informado o Diretório onde serão salvos os arquivos recebidos.Para Rotas de Download de Arquivos: Deve ser informado o Diretório onde estão fisicamente os arquivos.O diretório pode ser "completo" (ex: "C:/tmp/files/"), ou "relativo", neste caso, será uma sub-pasta dentro do projeto onde está rodando o Mock. Por exemplo, se for informado "uploads/", e o mock estiver no projeto "C:/THF/totvs-obrig-fisc/thf2/", o caminho considerado será: "C:/THF/totvs-obrig-fisc/thf2/uploads/".Observação: O diretório deve existir.|Ex1:"C:/arquivos/upload/"Ex2:"files/"|

Customizando o Response

Para as rotas customizadas que possuem o responseType igual a "object", é possível mudar o comportamento do response para, por exemplo, retornar uma mensagem de erro. Para isto, basta incluir os atributos abaixo na lista configurada no parâmetro "database" da rota: |Atributo|Descrição|Exemplos| |--|--|--| |statusCodeResponse(number)|Permite informar o Status Code do response. Se não informado, será considerado 200.|"statusCodeResponse": 400| |errorResponse(string)|Mensagem de erro retornada no Response. A mensagem será retornada no formato de Erro padrão TOTVS.|"errorResponse": "Não foi possível bloquear o cliente 3 !"|

Exemplo da Configuração de Rotas Customizadas

Segue abaixo uma tabela com exemplos de rotas customizadas: |Rota|Descrição| |--|--| |nextId|Simula o retorno de uma informação específica. Neste exemplo, retorna o próximo código do cliente. Que foi configurado no database "db_nextId" como 12.Exemplo:Requisição: GET /customer/nextIdRetorno: { "code": 12 }| |block|Simula a execução de uma ação no BackEnd, que retorna uma informação ou erro, com base em um parâmetro enviado. Neste exemplo, simula o bloqueio de um cliente. O código do cliente é enviado como PathParam que foi configurado na rota como ":idParam", desta forma, a lista "db_block" configurada no "database" da rota é filtrada por este parâmetro, já que ele possui uma atributo com o mesmo nome. Neste exemplo, as informações do "database" não são alteradas, é apenas uma simulação de retorno de erro.Exemplo 1:Requisição: POST /customer/1/blockRetorno: StatusCode: 200Exemplo 2:Requisição: POST /customer/3/blockRetorno: StatusCode: 400 - Erro: Não foi possível bloquear o cliente 3 !Exemplo 3:Requisição: POST /customer/6/blockRetorno: StatusCode: 500 - Erro: Usuário já está bloqueado !| |duplic|Simula o envio de uma informação que é salva no banco dados. Neste exemplo, simula a duplicação de um cliente. Neste caso, é enviado no Payload os dados de um cliente, que é salvo no banco "db_duplic" que foi configurado no parâmetro "database" da rota.Exemplo:Requisição: POST /customer/3/duplicPayload: { "code": 3, "shortName": "Adonias", "name": "Adonias Oliveira", "country": "USA", "status": 2 }Ação: A informação enviada no Payload será salva no parâmetro "db_duplic" do arquivo de configuração da entidade.| |totalByStatus|Simula uma Requisição que calcula a quantidade de Clientes por Status. Neste exemplo, é executada a função "get" do programa customer.js, que foi configurado no parâmetro script, para realizar o cálculo. A lista de cliente considerada será a database, que foi configurada no parâmetro database.Exemplo:Requisição: GET /customer/totBySatusRetorno: [ { "status": 2, "total": 2 }, { "status": 3, "total": 1 } ]| |changeStatus|Simula a alteração de Status do Cliente. Neste exemplo, é executada a função "post" do programa customer.js, que foi configurado no parâmetro script, para realizar a alteração. O novo status será enviado no Payload da Requisição. A lista de cliente considerada será a database, que foi configurada no parâmetro database.Exemplo:Requisição: POST /customer/3/changeStatusPayload: { "status": 1 }Ação: O Status do Cliente 3 será alterado para 1 e alteração será salva na lista de cliente configurado no parâmetro database.| |upload|Simula o envio de arquivos via Upload, que são salvos fisicamente no diretório "uploads/" existente dentro do projeto do Mock, que foi configurado no parâmetro "directory". As informações dos arquivos (nome, diretório, tamanho, etc...) são salvos no banco "db_photo", que foi configurado no parâmetro "database" da rota. Ao salvar o arquivo no diretório, ele é renomeado para conter também a data atual, conforme configurado no parâmetro "fileName".Exemplo:Requisição: POST /customer/photoUpload: Arquivo: joao.jpgAção: O arquivo será salvo no diretório: C:/THF/mock-totvs-builder/uploads/, com o nome joao_2020-06-13.jpg. E as informações do arquivo, serão salvas no parâmetro db_photo.| |image|Simula o download de imagens no FrontEnd, que estão fisicamente no diretório "images/" existente dentro do projeto do Mock, que foi configurado no parâmetro "directory". Na requisição é enviado um PathParam com o nome da imagem, conforme configurado no parâmetro "path" (:imageId). Esta parâmetro é utilizado para determinar o nome do arquivo, conforme configurado no parâmetro "fileName" (#imageId#). No response será retornado o arquivo de imagem conforme configurado no parâmetro "responseType".Exemplo:Requisição: GET /customer/photo/maria.jpgRetorno: Arquivo: maria.jpg|

Configuração:

Arquivo: data/customer.json

{
	"entityName": "customer",
	"entityLabel": "Cliente",
	"keys": [ "code" ],
	"customRoutes": [
		{
			"name": "nextId",
			"method": "GET",
			"path": "/nextId",
			"responseType": "object",
			"database": "db_nextId"
		},
		{
			"name": "block",
			"method": "POST",
			"path": "/:idParam/block",
			"responseType": "object",
			"database": "db_block"
		},
		{
			"name": "duplic",
			"method": "POST",
			"path": "/:idParam/duplic",
			"database": "db_duplic"
		},
		{
			"name": "totalByStatus",
			"method": "GET",
			"path": "/totBySatus",
			"script": "customer.js",
			"database": "database"
		},
		{
			"name": "changeStatus",
			"method": "POST",
			"path": "/:idParam/changeStatus",
			"script": "customer.js",
			"database": "database"
		},
		{
			"name": "upload",
			"method": "POST",
			"path": "/photo",
			"fileParam": {
				"fileName": "#file#_#today#",
				"directory": "uploads/"
			},
			"database": "db_photo"
		},
		{
			"name": "image",
			"method": "GET",
			"path": "/photo/:imageId",
			"fileParam": {
				"fileName": "#imageId#",
				"directory": "images/"
			},
			"responseType": "file"
		}
	],
	"database": [
		{
			"code": 1,
			"shortName": "João",
			"name": "Joãozinho da Silva",
			"country": "BRA",
			"status": 2
		},
		{
			"code": 2,
			"shortName": "Maria",
			"name": "Maria Barbosa",
			"country": "BRA",
			"status": 3
		},
		{
			"code": 3,
			"shortName": "Adonias",
			"name": "Adonias Ribeiro",
			"country": "BRA",
			"status": 2
		}
	],
	"db_nextId": [
		{
			"code": 12
		}
	],
	"db_block": [
		{
			"idParam": 1,
			"statusCodeResponse": 200
		},
		{
			"idParam": 3,
			"statusCodeResponse": 400,
			"errorResponse": "Não foi possível bloquear o cliente 3 !"
		},
		{
			"idParam": 6,
			"statusCodeResponse": 500,
			"errorResponse": "Usuário já está bloqueado !"
		}
	],
	"db_duplic": [
	],
	"db_photo": [
	]
}

Arquivo: data/customer.js

module.exports = {

	get(paramPath, queryParam, database) {
		let totStatus = [];
		database.forEach(customer => {
			let status = totStatus.find(st => st.status === customer.status);
			if (!status) {
				totStatus.push({ status: customer.status, total: 1 });
			} else {
				status.total += 1;
			}
		});

		return {
			statusCode: 200,
			response: { items: totStatus }
		}
	},

	post(paramPath, queryParam, payload, database) {
		let customer = database.find(cust => cust.code == paramPath.idParam);
		if (customer) {
			customer.status = payload.status;
		}

		return {
			statusCode: 200,
			response: {},
			database: database
		}
	}
};

Configurando Validações Customizadas

É possível criar validações que serão executadas sobre os parâmetros recebidos na requisição ou sobre os dados retornados por ela. Desta forma, é possível simular as validações retornadas pelo BackEnd, para verificar o comportamento da tela quando ocorre algum erro de negócio. Para criar as validações, basta incluir o parâmetro "customValidation" no arquivo de configuração da Entidade e as respectivas validações. Cada validação, deve respeitar a configuração conforme tabela abaixo: |Parâmetro|Obrig?|Descrição|Exemplos| |--|--|--|--| |name(string)|Sim|Um nome qualquer para identificar a Validação. Será apresentado no Help da mensagem de Erro.Observação: O nome deve ser único, isto é, não deve existir outra validação com o mesmo nome.|"vld_block"| |method(array)|Não|Indica sobre quais Métodos da Requisição a validação deve ser executada, podendo ser informado um ou vários. Por exemplo, se for informado "DELETE", a validação somente será executada quando receber um requisição com este método.É possível indicar os seguintes métodos: "GET", "PUT", "POST" e/ou "DELETE".Caso não seja informado, a validação será realizada sobre todas as requisições, independentemente do método.|["PUT", "POST", "DELETE"]| |route(array)|Não|Indica sobre quais rotas a validação deve ser executada, podendo ser informada uma ou várias. Por exemplo, se for informado "create", a validação somente será executada sobre a rota de create.Deve ser informado o nome da rota, podendo ser uma Pré-Definida (ver tópico: Rotas Pré-definidas, coluna name) ou uma Customizada (ver tópico: Configurando Rotas Customizadas, parâmetro name).Caso não seja informada, a validação será realizada sobre todas as rotas.|["update", "delete", "duplic"]| |from(array)|Não|Indica sobre quais Parâmetros da Requisição a validação deve ser executada, podendo ser informado um ou vários. Por exemplo, se for informado "pathParam", a validação será executada sobre os PathParams da requisição.É possível indicar os parâmetros enviados pela requisição, informando: "pathParam", "queryParam", "payload" e/ou os dados que foram acessados pela requisição, informando: "database".Caso não seja informado, a validação será realizada sobre todos os parâmetros da requisição e os dados acessados por ela.Observação: Quando for informado "database" será considerando os dados conforme o tipo de rota da requisição. Se for uma Rota Pré-definida, será considerando o parâmetro "database" do arquivo de Configuração da Entidade. Se for uma Rota Customizada, será considerando o parâmetro "database" configurado na rota.|["pathParam", "queryParam"]| |field(array)|Sim|Indica sobre quais campos a validação deve ser executada, podendo ser informado um ou vários.Este parâmetro trabalha em conjunto com o parâmetro "from". Por exemplo, se no "from" for informado "queryParam", e no "filed" for informado "branch", indica que a validação será executada sobre o campo "branch" que foi enviado como um queryParam.Quando no "from" for informado "database", a validação será executada sobre o campo com o mesmo nome que exista nos registros do "database". Por exemplo, se for informando no "from" o valor "code", a validação será executada sobre o campo "code" de todos os registros acessados pela requisição que vieram do "database".|["branch", "code", "currency"]| |operation(string)|Sim|Indica o tipo de validação que deve ser executada, considerando que o valor da campo informado no parâmetro "field" deve ser: igual á, maior que, diferente de, etc...Verificar no tópico "Operadores de Validação" todos os operadores disponíveis.|"!="| |value(string)|Sim|Valor que será utilizado para comparação com o conteúdo dos campos parametrizados em "field".Observação: Para que a comparação funcione corretamente, o conteúdo deve ser do mesmo tipo do campo.|"10"| |msgError(string)|Sim|Mensagem que será apresentada ao usuário se a validação for atendida. Esta mensagem será retornada para o FrontEnd no formato padrão de erro TOTVS. O código da mensagem será 400 e a mensagem e o help serão os mesmos, mas no help será incluído o nome da validação (parâmetro "name").|"Cliente está Bloqueado !"|

Operadores de Validação

O operador de validação é utilizado para comparar o valor dos campos informados no parâmetro "field" com o valor informado no parâmetro "value" da validação customizada. Segue abaixo a lista dos Operadores disponíveis: |Operador|Descrição|Observação| |--|--|--| |=|Igual a|O conteúdo do campo deve ser igual ao valor parametrizado.| |!=|Diferente de|O conteúdo do campo deve ser diferente do valor parametrizado.| |>|Maior que|O conteúdo do campo deve ser maior que o valor parametrizado.| |>=|Maior ou igual a|O conteúdo do campo deve ser maior ou igual ao valor parametrizado.| |<|Menor que|O conteúdo do campo deve ser menor que o valor parametrizado.| |<=|Menor ou igual a|O conteúdo do campo deve ser menor ou igual ao valor parametrizado.| |begins|Começa com|O conteúdo do campo deve começar pelo valor parametrizado.Observação: Somente disponível para campos do tipo caracter.| |!begins|Não começa com|O conteúdo do campo não deve começar pelo valor parametrizado.Observação: Somente disponível para campos do tipo caracter.| |contains|Contêm|O conteúdo do campo deve conter o valor parametrizado.Observação: Somente disponível para campos do tipo caracter.| |!contains|Não contêm|O conteúdo do campo não deve conter o valor parametrizado.Observação: Somente disponível para campos do tipo caracter.| |required|Obrigatório|Indica se o campo deve ter um conteúdo válido ou não. Se o valor parametrizado na validação (parâmetro "value") for "true", o campo deve existir e ter um conteúdo válido. Se o valor parametrizado for "false", o campo não deve existir ou deve ter um conteúdo inválido.

Observação: Para campos do tipo caracter, a comparação não é case sensitive.

Execução das Validações

A execução das validações será realizada em momentos diferentes conforme o método da Requisição e o tipo da rota, tendo um comportamento conforme tabela abaixo: |Método|Tipo Rota|Descrição| |--|--|--| |GET (Query)|Pré-definidas|Serão validadas somente as informações enviadas nos PathParams e QueryParams. Se a validação for atendida, os dados não serão lidos e será retornada a mensagem de erro parametrizada.| |GET|Pré-definidas|Primeiramente serão validadas as informações enviadas nos PathParams e QueryParams. Se a validação for atendida, o registro não será lido e sim, será retornada a mensagem de erro parametrizada.Caso contrário, o registro será lido e antes de retornar os dados, eles serão validados.Caso a validação seja atendida, será retornada a mensagem de erro parametrizada.| |POST (create)|Pré-definidas|Neste caso não é enviado PathParams, mas para validação, a chave da tabela (parâmetro "keys") será considerado com um PathParams para realizar a validação. Além da chave, serão validadas as informações enviadas no Payload. Se a validação for atendida, o registro não será incluído e será retornada a mensagem de erro parametrizada.| |PUT (update)|Pré-definidas|Primeiramente serão validadas as informações enviadas no PathParams. Se a validação for atendida, será retornada a mensagem de erro parametrizada.Caso contrário, o registro será lido e antes de alterá-lo, as informações dele serão validadas. Caso a validação seja atendida, o registro não será alterado e será retornada a mensagem de erro parametrizada.| |DELETE|Pré-definidas|Primeiramente serão validadas as informações enviadas no PathParams. Se a validação for atendida, será retornada a mensagem de erro parametrizada.Caso contrário, o registro será lido e antes de eliminá-lo, as informações dele serão validadas. Caso a validação seja atendida, o registro não será eliminado e será retornada a mensagem de erro parametrizada.| |GET|Customizada|Primeiramente serão validadas as informações enviadas nos PathParams e QueryParams. Se a validação for atendida, os registros não serão lidos e sim, será retornada a mensagem de erro parametrizada.Caso contrário, todos os registros lidos serão validados e antes de retornar os dados, eles serão validados.Caso a validação seja atendida, eles não serão retornados e sim a mensagem de erro parametrizada.| |POST|Customizada|Primeiramente serão validadas as informações enviadas nos PathParams, QueryParams e Payload. Se a validação for atendida, será retornada a mensagem de erro parametrizada.Depois disto, caso tenha sido parametrizado um database para rota, os registros selecionados serão validados. Se a validação for atendida, será retornada a mensagem de erro parametrizada.|

Observações:

  • Caso a validação seja atendida, será retornada uma mensagem no formato de Erro padrão TOTVS, com o status 400;
  • Caso mais de uma validação seja atendida na mesma requisição, os erros serão agrupados e estarão disponíveis nos detalhes do erro.

Exemplo da Configuração de Validações Customizadas

Segue abaixo uma tabela com exemplos de validações customizadas: |Validação|Descrição| |--|--| |vld_block|Simula a validação para, não permitir alterar ou excluir um cliente que esteja bloqueado.Será executada sobre os métodos "PUT" e "DELETE" conforme parametrizado em "method".Serão considerados os dados acessados no database, conforme parametrizado em "from".Dos dados acessados, será considerado o campo "status" conforme parametrizado em "field".Para validação, será considerado como cliente bloqueado, quando o campo for igual a "3" (parametrizado em "operation" e "value").Se a validação for atendida, será retornada a mensagem de erro parametrizada em "msgError".Exemplo:Requisição: DELETE /customer/2Retorno: { code: 400, message: 'Cliente está Bloqueado (status) !' }| |vld_big_code|Simula a validação para não permitir buscar clientes onde o código seja maior que 999.Será executada sobre o método "GET" conforme parametrizado em "method".Serão considerados os dados enviados no PathParam, conforme parametrizado em "from".Será considerado o parâmetro "id" do PathParam (parâmetro da rota) conforme parametrizado em "field".Para validação, será verificado se o id é maior ou igual a "999" (parametrizado em "operation" e "value").Se a validação for atendida, será retornada a mensagem de erro parametrizada em "msgError".Exemplo:Requisição: GET /customer/1923Retorno: { code: 400, message: 'Código do cliente deve ser menor que 999 (id) !' }| |vld_prm_obr|Simula a validação de campos obrigatórios em uma inclusão ou alteração.Serão consideradas as rotas "create" e "update" conforme parametrizado em "route".Serão considerados os dados enviados no Payload, conforme parametrizado em "from".Dos dados enviados, serão considerados os campos "name" e "status" conforme parametrizado em "field".Para validação, será verificado se os campos foram enviados e possuem um valor válido (requered = true), conforme parametrizado em "operation" e "value".Se a validação for atendida, será retornada a mensagem de erro parametrizada em "msgError".Exemplo:Requisição: POST /customerPayload: { "code": 10, "shortName": "Adonias", "status": 1 }Retorno: { code: 400, message: 'Campos obrigatório (name) !' }|

Configuração:

Arquivo: data/customer.json

{
	"entityName": "customer",
	"entityLabel": "Cliente",
	"keys": [ "code" ],
	"customValidation": [
		{
			"name": "vld_block",
			"method": [ "PUT", "DELETE" ],
			"from": [ "database" ],
			"field": [ "status" ],
			"operation": "=",
			"value": 3,
			"msgError": "Cliente está Bloqueado !"
		},
		{
			"name": "vld_big_code",
			"method": [ "GET" ],
			"from": [ "pathParam" ],
			"field": [ "id" ],
			"operation": ">=",
			"value": "999",
			"msgError": "Código do cliente deve ser menor que 999 !"
		},
		{
			"name": "vld_prm_obr",
			"route": [ "create", "update" ],
			"from": [ "payload" ],
			"field": [ "name", "status" ],
			"operation": "required",
			"value": "true",
			"msgError": "Campos obrigatório !"
		}
	],
	"database": [
		{
			"code": 1,
			"shortName": "João",
			"name": "Joãozinho da Silva",
			"country": "BRA",
			"status": 2
		},
		{
			"code": 2,
			"shortName": "Maria",
			"name": "Maria Barbosa",
			"country": "BRA",
			"status": 3
		}
	]
}

Executando o mock-totvs-builder

Existe duas formas de executar o mock-totvs-builder, através de um projeto client, ou incorporando ao seu projeto.

Projeto mock-totvs-builder-client

Projeto utilizando para executar o mock-totvs-builder, desta forma, serão carregados duas seções do Visual Studio. Uma com o seu projeto e outro com o projeto do Mock. O mock-totvs-builder-client está disponível endereço abaixo, basta baixar o projeto e seguir o README. https://github.com/ModernizaDatasul/mock-totvs-builder-client/

Incorporando ao seu Projeto

Para incorporar o mock-totvs-builder ao seu projeto, basta seguir os passos abaixo:

  1. Instalar o mock-totvs-builder e o nodemon (biblioteca que controla o reload do mock) no projeto, como uma dependência de Desenvolvimento, executando os comandos abaixo no terminal:

    npm install --save-dev mock-totvs-builder
    npm install --save-dev nodemon@1
  2. Na pasta principal do seu projeto (mesma pasta onde está o package.json) criar um novo arquivo chamado "start-mock.js", com o seguinte conteúdo:

    // Inicializa o Mock
    const mockServer = require('mock-totvs-builder');
    const server = mockServer.startMock(__dirname);
    
    // Carrega o Server
    if (server) {
    	server.listen(3000, () => { console.log('Mock no AR, Porta: 3000'); });
    } else {
    	console.log('Não foi possível carregar o Mock, verifique os arquivos de configuração (data) !');
    }
  3. Nesta mesma pasta, criar um pasta chamada "data" onde deverão ser salvos os arquivos de configuração das Entidades, conforme descrito no início da documentação.

  4. Criar um atalho para execução do mock, para isto:

    • Abrir o arquivo "package.json";
    • Logo no início existe uma grupo chamado "scripts";
    • incluir a linha: "mock": "nodemon start-mock",
  5. A utilização do Mock no projeto vai funcionar da seguinte forma:

    • Com o seu Projeto aberto no Visual Studio, deverão ser abertos dois Terminais;
    • Um será utilizado para carregar a sua aplicação e o outro para carregar o mock;
    • Para carregar o mock, utilizar o comando: npm run mock
    • Deve aparecer a mensagem: "Mock no AR, Porta: 3000".
  6. Para verificar as entidades configuradas no mock, basta:

    • Abrir um Navegador Web e acessar o endereço: http://localhost:3000/
    • Deve aparecer: MOCK TOTVS BUILDER - No Ar !! e as Entidades configuradas.

Implementações Futuras

  • Validador do Arquivo de Configuração
  • Tratamento do expandables (por padrão não terá, mas poderá ser "ligado" via arq config)
  • Atributo auto incrementado
  • Variáveis no arquivo de configuração (ex: #today#)
  • Edição Entidade Config via html.