Mudanças entre as edições de "PHSYS API"

Linha 1: Linha 1:
==='''Conceito'''===
+
==='''Introducao'''===
A PHSYS API é uma camada de integração que permite a comunicação entre sistemas externos e o PHERP por meio de requisições REST. Diferente de uma API tradicional rígida, a PHSYS API funciona com um modelo dinâmico e configurável, onde cada endpoint é cadastrado diretamente no [[Servidor_de_Aplicação|servidor de aplicação]] e associado a procedimentos internos do sistema. Esse modelo permite que novas integrações sejam criadas, bastando configurar o endpoint, a classe executada e os parâmetros envolvidos.
 
  
O funcionamento da PHSYS API consiste, portanto, em um fluxo simples: o cliente envia uma requisição REST para um endpoint cadastrado, o servidor processa a requisição conforme as regras definidas e executa o procedimento interno correspondente. Dessa forma, a API garante flexibilidade, segurança e integração direta com os recursos internos do ERP.
+
Este exemplo mostra como configurar um unico endpoint de API para executar varios procedimentos internos, usando o campo MetodoScript no body da requisicao.
  
==='''URL Base'''===
+
A proposta e ter um endpoint unico, por exemplo:
  
A URL Base da PHSYS API corresponde ao endereço do servidor de aplicação onde o serviço está sendo executado, seguido do caminho padrão '''/api''', que identifica o módulo de integração da plataforma. Todas as requisições enviadas ao PHSYS devem utilizar essa URL Base como ponto inicial, adicionando ao final o endpoint configurado no servidor.
+
<code>http://localhost:211/api/solicitacoes</code>
  
A estrutura geral da URL Base é:
+
e dentro do script, direcionar a execucao para:
http://<endereço_do_servidor>:<porta>/api/<endpoint>
 
  
Exemplo em ambiente local:
+
* Cadastrar
http://localhost:211/api/IntegracaoScriptEspecifico
+
* Consultar
 +
* Cancelar
  
Nessa composição:
+
Esse modelo e util quando os procedimentos pertencem ao mesmo contexto funcional e compartilham a mesma autenticacao e URL de integracao.
  
'''localhost:''' Endereço do servidor.
+
==='''Modelo de Integracao Personalizado'''===
'''211:''' Porta onde o serviço do PH Server está sendo executado.
 
'''/api/:''' Indica o caminho de integração da PHSYS API.
 
'''IntegracaoScriptEspecifico:''' Endpoint configurado pelo administrador no servidor de aplicação.
 
  
Cada endpoint cadastrado no servidor se torna acessível adicionando seu nome ao final da URL Base, permitindo assim organizar diferentes integrações de forma clara e padronizada.
+
No cadastro do endpoint no PHServerConf:
  
==='''EndPoints'''===
+
* Modelo de integracao: Personalizado
 +
* Classe: script especifico
 +
* Procedimento: GetMetodo
 +
* Exige token: Sim (opcional, recomendado)
  
Os endpoints da PHSYS API são rotas configuradas no servidor de aplicação que representam os pontos de entrada das requisições enviadas pelos sistemas integrados. Cada endpoint define qual procedimento interno do PHERP será executado quando uma requisição REST for recebida, bem como suas regras de autenticação, base de dados e usuário do PHERP responsável pela execução.
+
Com isso, toda requisicao ao endpoint passa pelo procedimento GetMetodo, que decide qual acao executar com base no body.
  
Após o cadastro, o endpoint passa a responder pelo nome configurado, permitindo que a aplicação cliente envie requisições diretamente para ele. A API então identifica o endpoint chamado, executa o procedimento interno associado.
+
==='''Cabecalhos Necessarios'''===
  
===='''Cadastro'''====
+
* Content-Type: application/json
O cadastro do endpoint é realizado diretamente no servidor de aplicação, onde, por meio da página '''EndPoints de API''', é possível visualizar os endpoints existentes, editar suas configurações ou criar novos conforme a necessidade da integração.
+
* Authorization: Bearer &lt;access_token&gt; (quando OAuth2 estiver habilitado)
  
Nesse cadastro, podem ser definidos o nome do endpoint que será exposto, bem como o usuário e a senha do PHERP que serão utilizados para executar os procedimentos internos vinculados à integração. Também é possível configurar a descrição, a base de dados utilizada durante o processamento e a situação de ativação, permitindo habilitar ou desabilitar o endpoint conforme o uso desejado.
+
==='''Estrutura da Requisicao'''===
  
====='''Modelo de Integração'''=====
+
URL:
O endpoint pode ser configurado com diferentes modelos de integração, que definem como o procedimento interno do PHERP será acionado quando a requisição for recebida.
 
  
:'''Personalizado:''' Neste modelo, o administrador informa diretamente a '''Classe''' e o '''Procedimento''' que serão executados quando o endpoint for chamado. A requisição não precisa enviar no body qual procedimento será utilizado, pois tudo já está definido no cadastro do endpoint. Também é possível configurar parâmetros fixos, que serão automaticamente enviados ao procedimento interno durante a execução.
+
<code>http://&lt;servidor&gt;:&lt;porta&gt;/api/solicitacoes</code>
:'''PHSYS:''' No modelo PHSYS, a própria requisição define qual procedimento será executado, utilizando um JSON no padrão interno da PHSYS. Nesse formato, o cliente especifica no body informações como classe, procedimento e parâmetros. O endpoint funciona como um ponto de entrada genérico, permitindo maior flexibilidade no envio das operações.
 
::'''Estrutura de body PHSYS:''' Essa é a estrutura padrão esperada no body para requisições em que o modelo de integração é '''PHSYS''', no qual as requisições devem ser enviadas via método POST. Para identificação de qual processo o servidor deve executar, é necessário informar qual a classe e qual o procedimento será executado. Dados como ID, empresa e parâmetros são opcionais, mas devem ser informados dependendo do processo que será executado pelo servidor.
 
  
::Os parâmetros a serem enviados abrangem nove tipos distintos, é importante observar a formatação esperada por cada um deles. Esses tipos são:
+
Metodo HTTP:
::*string
 
::*integer
 
::*largeint
 
::*stream
 
::*boolean '''[ true | false ]'''
 
::*time '''[ hh:mm:ss ]'''
 
::*date '''[ yyyy-mm-dd ]'''
 
::*datetime '''[ yyyy-mm-dd hh:mm:ss ]'''
 
::*float '''[ 0.00000000 ]'''
 
  
::Sendo assim, O formato do JSON no corpo (body) da requisição deve possuir a seguinte estrutura:
+
<code>POST</code>
  
{"Classe": "TPHSPedido",
+
Body base:
  "Procedimento": "Imprimir",
 
  "ID": 20,
 
  "Empresa": 1,
 
  “Parametros”:[
 
        {
 
        "Nome": "Texto",
 
      "Tipo": "string",
 
      "Valor": "Isso é um teste"
 
    },
 
    {
 
        "Nome": "Numero",
 
      "Tipo": "integer",
 
      "Valor": 1
 
        }
 
  ]
 
}
 
  
::'''Parâmetros:'''
+
<pre>
::*'''Classe:''' Nome da classe a ser invocada no servidor, classe pode ser enviada no parametros também.
+
{
::*'''Procedimento:''' Nome do procedimento a ser executado na classe, procedimento pode ser enviada no parametros também.
+
  "MetodoScript": "Cadastrar | Consultar | Cancelar",
::*'''ID (Opcional):''' Identificador único associado à requisição.
+
  "...": "demais campos conforme cada metodo"
::*'''Empresa (Opcional):''' Identificador da empresa relacionada à requisição.
+
}
::*'''Parametros (Opcional):''' Informações adicionais resultantes do processamento.
+
</pre>
:::*'''Nome:''' Identificação do parâmetro.
 
:::*'''Tipo:''' Tipo de dado associado ao parâmetro.
 
:::*'''Valor:''' Valor do parâmetro, podendo ser uma string ou um stream (no caso do parâmetro "Arquivo").
 
  
====='''Autenticação OAuth2'''=====
+
==='''Exemplo de Bodies'''===
O endpoint pode ser configurado para utilizar autenticação baseada no padrão OAuth2. Quando essa opção está habilitada, a requisição só será processada se apresentar um token Bearer válido no cabeçalho. Esse mecanismo garante maior segurança no acesso aos procedimentos internos do PHERP. A autenticação é controlada pelos seguintes parâmetros no cadastro do endpoint:
 
  
:'''Exige Token:''' Quando ativado, o endpoint passa a aceitar apenas requisições que enviem um token válido no cabeçalho Authorization: Bearer <token>. Caso o token esteja ausente, expirado ou inválido, a API rejeita a requisição automaticamente.
+
==='''1) Cadastrar'''===
:'''Minutos de validade do token:''' Define por quanto tempo o token gerado permanecerá válido. Após esse período, será necessário solicitar um novo token para continuar realizando requisições ao endpoint protegido.
 
  
Além disso, a autenticação utiliza as credenciais de '''ClientID''' e '''ClientSecret''', que são geradas automaticamente no momento do cadastro do endpoint e são únicas para cada integração. O ClientID identifica o cliente solicitante, enquanto o ClientSecret é a chave secreta associada a ele. É importante destacar que '''o ClientSecret é exibido apenas uma vez, caso seja perdido, será necessário gerar um novo'''. Ambos são utilizados no processo de geração do token para garantir que somente clientes autorizados tenham acesso ao endpoint.
+
<pre>
 +
{
 +
  "MetodoScript": "Cadastrar",
 +
  "Cliente": "2",
 +
  "Solicitante": "2",
 +
  "TiposSolicitacao": "3",
 +
  "Requisito": "2",
 +
  "Prioridade": "2",
 +
  "DescricaoResumida": "Solicitacao de exemplo",
 +
  "Descricao": "Descricao detalhada da solicitacao"
 +
}
 +
</pre>
  
Para solicitar o token, o cliente deve realizar uma requisição ao endpoint exclusivo de autenticação da PHSYS API, enviando o client_id e client_secret no body para obtenção de um token válido.
+
==='''2) Consultar'''===
  
Exemplo de Requisição de Token:
+
<pre>
Requisição:
+
{
+
  "MetodoScript": "Consultar",
curl -X POST "http://localhost:211/api/auth/token" ^
+
   "SolicitacaoID": "150"
  -H "Content-Type: application/json" ^
+
}
  -d "{\"client_id\":\"MjQ2MDg2NzItQjQxOC00N0IwLUI1MUYtNzE4QjgwRUNCNDZB\",                
+
</pre>
        \"client_secret\":\"REYyMDA1MEItODkzOS00RjZCLTk3OEYtMDNFOUNEOEY4MEVERURGMTEzNTAtQjQwOS00OTk2LUFBN0EtMkVGNUZENTM5NUY5\"}"
 
 
Resposta:
 
 
{ "access_token": "1f0e169c1b63c34236d3dc7f6b841e5b5ac066c492eb771fdf18b357a1b4f129",    
 
  "token_type": "Bearer"
 
  "expires_in": 900 }
 
  
Com o '''access_token''' nas proximas requisições será necessário enviar no header da reqisição com o Authorization: Bearer + <access_token>, caso não encaminhado, será retornado que não está autorizado.
+
==='''3) Cancelar'''===
  
curl -X GET "http://localhost:211/api/IntegracaoScriptEspecifico" -H ^
+
<pre>
"Authorization: Bearer 1f0e169c1b63c34236d3dc7f6b841e5b5ac066c492eb771fdf18b357a1b4f129"
+
{
 +
  "MetodoScript": "Cancelar",
 +
  "SolicitacaoID": "150",
 +
  "Motivo": "Solicitacao aberta em duplicidade"
 +
}
 +
</pre>
  
Caso o cabeçalho não seja enviado corretamente, a API retornará erro de autorização.
+
==='''Exemplo de Script'''===
  
Em resumo, ao habilitar OAuth2, o endpoint passa a operar com uma camada adicional de segurança, exigindo que o cliente obtenha um token válido antes de consumir qualquer recurso da PHSYS API.
+
<pre>
 +
procedure GetMetodo;
 +
var
 +
  Metodo: String;
 +
begin
 +
  Metodo := UpperCase(ObterMetodoFromBody);
  
'''Fluxograma de autenticação OAuth2 na API'''
+
  if (Metodo = 'CADASTRAR') then
 +
    Cadastrar
 +
  else if (Metodo = 'CONSULTAR') then
 +
    Consultar
 +
  else if (Metodo = 'CANCELAR') then
 +
    Cancelar
 +
  else
 +
    ErroValidacao('Processo invalido. Metodo informado: ' + Metodo);
 +
end;
  
<img src="https://wiki.phsys.com.br/images/WIKI/API/Fluxograma_Autenticacao_API_SemFundo.svg" alt="Imagem do esquema de autenticação de API" style="width:700px">
+
function ObterMetodoFromBody: String;
 +
var
 +
  Body: String;
 +
  JsonObj: TPHJson;
 +
begin
 +
  Body := Trim(GetBody);
  
===='''Resposta da Requisição'''====
+
  if (Body = '') then
O parâmetro Result determina o conteúdo que será retornado ao cliente após a chamada ao endpoint. Em scripts específicos, é possível definir esse valor de retorno utilizando o comando abaixo, atribuindo qualquer texto ou JSON conforme a necessidade da integração:
+
    ErroValidacao('Faltou informar o body da requisicao.');
  
ParamByName('Result').AsString := <texto ou JSON>;
+
  JsonObj := TPHJson.Create;
 +
  try
 +
    JsonObj.LerJson(Body);
 +
    Result := Trim(JsonObj.ElementoDoNome('MetodoScript').Texto);
 +
  finally
 +
    JsonObj.Free;
 +
  end;
 +
end;
  
Esse mecanismo permite que o endpoint responda com um JSON de sucesso, com dados processados ou com qualquer outra informação relevante, garantindo uma resposta totalmente personalizada de acordo com a lógica implementada no procedimento. Isso permite que o endpoint seja totalmente personalizado, retornando exatamente o que o integrador necessita.
+
function MontarRetornoSucesso(const Detalhes: String): String;
 +
begin
 +
  Result :=
 +
    '{' +
 +
      '"status":"sucesso",' +
 +
      '"detalhes":"' + Detalhes + '"' +
 +
    '}';
 +
end;
  
===='''GetBody'''====
+
function MontarRetornoErro(const Detalhes: String): String;
O método GetBody permite acessar o body enviado na requisição ao endpoint. Quando o modelo de integração é personalizado, o script pode ler e manipular livremente o conteúdo recebido, independentemente do formato encaminhado pelo cliente. Isso possibilita utilizar o body para validações, transformações, extrações de dados ou qualquer outro tipo de processamento necessário, oferecendo flexibilidade total para trabalhar com diferentes estruturas e requisitos de integração.
+
begin
 +
  Result :=
 +
    '{' +
 +
      '"status":"erro",' +
 +
      '"detalhes":"' + Detalhes + '"' +
 +
    '}';
 +
end;
  
==='''Exemplos'''===
+
procedure Cadastrar;
 +
var
 +
  Body: String;
 +
  JsonObj: TPHJson;
 +
  SolicitacaoObj: TPHServerClass;
 +
  Msg: String;
 +
begin
 +
  Body := Trim(GetBody);
  
====='''Modelo de Integração [Personalizado] '''=====
+
  JsonObj := TPHJson.Create;
:[[Exemplo de Endpoint para Execução de Múltiplos Procedimentos Com PHSYS API | Endpoint para Execução de Múltiplos Procedimentos]]
+
  try
:[[Exemplo de Cadastro de Pedido de Venda Com PHSYS API | Cadastro de Pedido de Venda ]]
+
    JsonObj.LerJson(Body);
:[[Exemplo de Consulta de Produto Com PHSYS API | Consulta de Produto ]]
 
:[[Exemplo de Deletar Produto Com PHSYS API | Deletar Produto ]]
 
:[[Exemplo de Consulta de Saldo de Produtos Com PHSYS API | Consulta de Saldo de Produtos ]]
 
  
====='''Modelo de Integração [PHSYS] '''=====
+
    SolicitacaoObj := NewPHServerClass('SOLICITACOES');
:[[Exemplo de Leitura de Registro de Pessoa Com PHSYS API|Leitura de Registro de Pessoa ]]
+
    try
:[[Exemplo de Gravação de Registro de Pessoa Com PHSYS API|Gravação de Registro de Pessoa ]]
+
      IniciarTransacao;
:[[Exemplo de Cadastro de Produto Com PHSYS API | Cadastro de Produto (OAuth2) ]]
+
      try
 +
        SolicitacaoObj.NovoRegistro;
 +
        SolicitacaoObj.CampoDoNome('PESSOA').AsLargeInt := StrToInt(JsonObj.ElementoDoNome('Cliente').Texto);
 +
        SolicitacaoObj.CampoDoNome('SOLICITANTE').AsLargeInt := StrToInt(JsonObj.ElementoDoNome('Solicitante').Texto);
 +
        SolicitacaoObj.CampoDoNome('TIPOSOLICITACAO').AsLargeInt := StrToInt(JsonObj.ElementoDoNome('TiposSolicitacao').Texto);
 +
        SolicitacaoObj.CampoDoNome('REQUISITO').AsLargeInt := StrToInt(JsonObj.ElementoDoNome('Requisito').Texto);
 +
        SolicitacaoObj.CampoDoNome('NIVELPRIORIDADE').AsLargeInt := StrToInt(JsonObj.ElementoDoNome('Prioridade').Texto);
 +
        SolicitacaoObj.CampoDoNome('NOME').AsString := JsonObj.ElementoDoNome('DescricaoResumida').Texto;
 +
        SolicitacaoObj.CampoDoNome('DESCRICAOPROBLEMA').AsString := JsonObj.ElementoDoNome('Descricao').Texto;
 +
        SolicitacaoObj.Salvar;
  
----
+
        ConfirmarTransacao;
 +
        Msg :=
 +
          '{' +
 +
            '"status":"sucesso",' +
 +
            '"detalhes":"Solicitacao cadastrada.",' +
 +
            '"SolicitacaoID":"' + IntToStr(SolicitacaoObj.CampoDoNome('ID').AsLargeInt) + '"' +
 +
          '}';
 +
      except
 +
        CancelarTransacao;
 +
        Msg := MontarRetornoErro('Erro ao cadastrar solicitacao: ' + ExceptionMessage);
 +
      end;
 +
    finally
 +
      SolicitacaoObj.Free;
 +
    end;
 +
  finally
 +
    JsonObj.Free;
 +
  end;
  
 +
  ParamByName('Result').AsString := Msg;
 +
end;
  
'''Assuntos Relacionados'''
+
procedure Consultar;
 +
var
 +
  Body: String;
 +
  JsonObj: TPHJson;
 +
  Q: TPHQuery;
 +
  SolicitacaoID: String;
 +
  Msg: String;
 +
begin
 +
  Body := Trim(GetBody);
  
[[Comunicação Client Com Servidor|Comunicação Client Com Servidor]]
+
  JsonObj := TPHJson.Create;
 +
  try
 +
    JsonObj.LerJson(Body);
 +
    SolicitacaoID := JsonObj.ElementoDoNome('SolicitacaoID').Texto;
 +
 
 +
    Q := NewPHQuery;
 +
    try
 +
      Q.Add('SELECT ID, NOME, DESCRICAOPROBLEMA, SITUACAO ' +
 +
            'FROM SOLICITACOES ' +
 +
            'WHERE ID = :ID');
 +
      Q.ParamByName('ID').AsLargeInt := StrToInt(SolicitacaoID);
 +
      Q.Open;
 +
 
 +
      if Q.Vazia then
 +
        Msg := MontarRetornoErro('Solicitacao nao encontrada.')
 +
      else
 +
        Msg :=
 +
          '{' +
 +
            '"status":"sucesso",' +
 +
            '"Solicitacao":{' +
 +
              '"ID":"' + Q.FieldByName('ID').AsString + '",' +
 +
              '"NOME":"' + Q.FieldByName('NOME').AsString + '",' +
 +
              '"DESCRICAO":"' + Q.FieldByName('DESCRICAOPROBLEMA').AsString + '",' +
 +
              '"SITUACAO":"' + Q.FieldByName('SITUACAO').AsString + '"' +
 +
            '}' +
 +
          '}';
 +
    finally
 +
      Q.Free;
 +
    end;
 +
  finally
 +
    JsonObj.Free;
 +
  end;
 +
 
 +
  ParamByName('Result').AsString := Msg;
 +
end;
 +
 
 +
procedure Cancelar;
 +
var
 +
  Body: String;
 +
  JsonObj: TPHJson;
 +
  SolicitacaoObj: TPHServerClass;
 +
  Msg: String;
 +
  SolicitacaoID: Int64;
 +
begin
 +
  Body := Trim(GetBody);
 +
 
 +
  JsonObj := TPHJson.Create;
 +
  try
 +
    JsonObj.LerJson(Body);
 +
    SolicitacaoID := StrToInt(JsonObj.ElementoDoNome('SolicitacaoID').Texto);
 +
 
 +
    SolicitacaoObj := NewPHServerClass('SOLICITACOES');
 +
    try
 +
      IniciarTransacao;
 +
      try
 +
        SolicitacaoObj.CampoDoNome('ID').AsLargeInt := SolicitacaoID;
 +
        SolicitacaoObj.LerRegistro;
 +
 
 +
        if (SolicitacaoObj.CampoDoNome('ID').AsLargeInt = 0) then
 +
          ErroValidacao('Solicitacao nao encontrada para cancelamento.');
 +
 
 +
        SolicitacaoObj.CampoDoNome('SITUACAO').AsString := 'C';
 +
        SolicitacaoObj.CampoDoNome('OBS').AsString := JsonObj.ElementoDoNome('Motivo').Texto;
 +
        SolicitacaoObj.Salvar;
 +
 
 +
        ConfirmarTransacao;
 +
        Msg := MontarRetornoSucesso('Solicitacao cancelada com sucesso.');
 +
      except
 +
        CancelarTransacao;
 +
        Msg := MontarRetornoErro('Erro ao cancelar solicitacao: ' + ExceptionMessage);
 +
      end;
 +
    finally
 +
      SolicitacaoObj.Free;
 +
    end;
 +
  finally
 +
    JsonObj.Free;
 +
  end;
 +
 
 +
  ParamByName('Result').AsString := Msg;
 +
end;
 +
 
 +
begin
 +
end.
 +
</pre>
 +
 
 +
==='''Exemplo de Envio (cURL)'''===
 +
 
 +
==='''Cadastrar'''===
 +
 
 +
<pre>
 +
curl -X POST "http://localhost:211/api/solicitacoes" ^
 +
  -H "Content-Type: application/json" ^
 +
  -H "Authorization: Bearer &lt;access_token&gt;" ^
 +
  -d "{\"MetodoScript\":\"Cadastrar\",\"Cliente\":\"2\",\"Solicitante\":\"2\",\"TiposSolicitacao\":\"3\",\"Requisito\":\"2\",\"Prioridade\":\"2\",\"DescricaoResumida\":\"Solicitacao de exemplo\",\"Descricao\":\"Descricao detalhada\"}"
 +
</pre>
 +
 
 +
==='''Consultar'''===
 +
 
 +
<pre>
 +
curl -X POST "http://localhost:211/api/solicitacoes" ^
 +
  -H "Content-Type: application/json" ^
 +
  -H "Authorization: Bearer &lt;access_token&gt;" ^
 +
  -d "{\"MetodoScript\":\"Consultar\",\"SolicitacaoID\":\"150\"}"
 +
</pre>
 +
 
 +
==='''Cancelar'''===
 +
 
 +
<pre>
 +
curl -X POST "http://localhost:211/api/solicitacoes" ^
 +
  -H "Content-Type: application/json" ^
 +
  -H "Authorization: Bearer &lt;access_token&gt;" ^
 +
  -d "{\"MetodoScript\":\"Cancelar\",\"SolicitacaoID\":\"150\",\"Motivo\":\"Duplicidade\"}"
 +
</pre>
 +
 
 +
==='''Resumo'''===
 +
 
 +
Com esse padrao, um unico endpoint consegue atender varias operacoes de um mesmo dominio, mantendo:
 +
 
 +
* Uma URL unica para integracao
 +
* Controle centralizado de autenticacao
 +
* Flexibilidade para evoluir os procedimentos no script
 +
 
 +
Para respostas personalizadas, utilize sempre:
 +
 
 +
<code>ParamByName('Result').AsString := &lt;texto ou JSON&gt;;</code>

Edição das 15h59min de 23 de julho de 2026

Introducao

Este exemplo mostra como configurar um unico endpoint de API para executar varios procedimentos internos, usando o campo MetodoScript no body da requisicao.

A proposta e ter um endpoint unico, por exemplo:

http://localhost:211/api/solicitacoes

e dentro do script, direcionar a execucao para:

  • Cadastrar
  • Consultar
  • Cancelar

Esse modelo e util quando os procedimentos pertencem ao mesmo contexto funcional e compartilham a mesma autenticacao e URL de integracao.

Modelo de Integracao Personalizado

No cadastro do endpoint no PHServerConf:

  • Modelo de integracao: Personalizado
  • Classe: script especifico
  • Procedimento: GetMetodo
  • Exige token: Sim (opcional, recomendado)

Com isso, toda requisicao ao endpoint passa pelo procedimento GetMetodo, que decide qual acao executar com base no body.

Cabecalhos Necessarios

  • Content-Type: application/json
  • Authorization: Bearer <access_token> (quando OAuth2 estiver habilitado)

Estrutura da Requisicao

URL:

http://<servidor>:<porta>/api/solicitacoes

Metodo HTTP:

POST

Body base:

{
  "MetodoScript": "Cadastrar | Consultar | Cancelar",
  "...": "demais campos conforme cada metodo"
}

Exemplo de Bodies

1) Cadastrar

{
  "MetodoScript": "Cadastrar",
  "Cliente": "2",
  "Solicitante": "2",
  "TiposSolicitacao": "3",
  "Requisito": "2",
  "Prioridade": "2",
  "DescricaoResumida": "Solicitacao de exemplo",
  "Descricao": "Descricao detalhada da solicitacao"
}

2) Consultar

{
  "MetodoScript": "Consultar",
  "SolicitacaoID": "150"
}

3) Cancelar

{
  "MetodoScript": "Cancelar",
  "SolicitacaoID": "150",
  "Motivo": "Solicitacao aberta em duplicidade"
}

Exemplo de Script

procedure GetMetodo;
var
  Metodo: String;
begin
  Metodo := UpperCase(ObterMetodoFromBody);

  if (Metodo = 'CADASTRAR') then
    Cadastrar
  else if (Metodo = 'CONSULTAR') then
    Consultar
  else if (Metodo = 'CANCELAR') then
    Cancelar
  else
    ErroValidacao('Processo invalido. Metodo informado: ' + Metodo);
end;

function ObterMetodoFromBody: String;
var
  Body: String;
  JsonObj: TPHJson;
begin
  Body := Trim(GetBody);

  if (Body = '') then
    ErroValidacao('Faltou informar o body da requisicao.');

  JsonObj := TPHJson.Create;
  try
    JsonObj.LerJson(Body);
    Result := Trim(JsonObj.ElementoDoNome('MetodoScript').Texto);
  finally
    JsonObj.Free;
  end;
end;

function MontarRetornoSucesso(const Detalhes: String): String;
begin
  Result :=
    '{' +
      '"status":"sucesso",' +
      '"detalhes":"' + Detalhes + '"' +
    '}';
end;

function MontarRetornoErro(const Detalhes: String): String;
begin
  Result :=
    '{' +
      '"status":"erro",' +
      '"detalhes":"' + Detalhes + '"' +
    '}';
end;

procedure Cadastrar;
var
  Body: String;
  JsonObj: TPHJson;
  SolicitacaoObj: TPHServerClass;
  Msg: String;
begin
  Body := Trim(GetBody);

  JsonObj := TPHJson.Create;
  try
    JsonObj.LerJson(Body);

    SolicitacaoObj := NewPHServerClass('SOLICITACOES');
    try
      IniciarTransacao;
      try
        SolicitacaoObj.NovoRegistro;
        SolicitacaoObj.CampoDoNome('PESSOA').AsLargeInt := StrToInt(JsonObj.ElementoDoNome('Cliente').Texto);
        SolicitacaoObj.CampoDoNome('SOLICITANTE').AsLargeInt := StrToInt(JsonObj.ElementoDoNome('Solicitante').Texto);
        SolicitacaoObj.CampoDoNome('TIPOSOLICITACAO').AsLargeInt := StrToInt(JsonObj.ElementoDoNome('TiposSolicitacao').Texto);
        SolicitacaoObj.CampoDoNome('REQUISITO').AsLargeInt := StrToInt(JsonObj.ElementoDoNome('Requisito').Texto);
        SolicitacaoObj.CampoDoNome('NIVELPRIORIDADE').AsLargeInt := StrToInt(JsonObj.ElementoDoNome('Prioridade').Texto);
        SolicitacaoObj.CampoDoNome('NOME').AsString := JsonObj.ElementoDoNome('DescricaoResumida').Texto;
        SolicitacaoObj.CampoDoNome('DESCRICAOPROBLEMA').AsString := JsonObj.ElementoDoNome('Descricao').Texto;
        SolicitacaoObj.Salvar;

        ConfirmarTransacao;
        Msg :=
          '{' +
            '"status":"sucesso",' +
            '"detalhes":"Solicitacao cadastrada.",' +
            '"SolicitacaoID":"' + IntToStr(SolicitacaoObj.CampoDoNome('ID').AsLargeInt) + '"' +
          '}';
      except
        CancelarTransacao;
        Msg := MontarRetornoErro('Erro ao cadastrar solicitacao: ' + ExceptionMessage);
      end;
    finally
      SolicitacaoObj.Free;
    end;
  finally
    JsonObj.Free;
  end;

  ParamByName('Result').AsString := Msg;
end;

procedure Consultar;
var
  Body: String;
  JsonObj: TPHJson;
  Q: TPHQuery;
  SolicitacaoID: String;
  Msg: String;
begin
  Body := Trim(GetBody);

  JsonObj := TPHJson.Create;
  try
    JsonObj.LerJson(Body);
    SolicitacaoID := JsonObj.ElementoDoNome('SolicitacaoID').Texto;

    Q := NewPHQuery;
    try
      Q.Add('SELECT ID, NOME, DESCRICAOPROBLEMA, SITUACAO ' +
            'FROM SOLICITACOES ' +
            'WHERE ID = :ID');
      Q.ParamByName('ID').AsLargeInt := StrToInt(SolicitacaoID);
      Q.Open;

      if Q.Vazia then
        Msg := MontarRetornoErro('Solicitacao nao encontrada.')
      else
        Msg :=
          '{' +
            '"status":"sucesso",' +
            '"Solicitacao":{' +
              '"ID":"' + Q.FieldByName('ID').AsString + '",' +
              '"NOME":"' + Q.FieldByName('NOME').AsString + '",' +
              '"DESCRICAO":"' + Q.FieldByName('DESCRICAOPROBLEMA').AsString + '",' +
              '"SITUACAO":"' + Q.FieldByName('SITUACAO').AsString + '"' +
            '}' +
          '}';
    finally
      Q.Free;
    end;
  finally
    JsonObj.Free;
  end;

  ParamByName('Result').AsString := Msg;
end;

procedure Cancelar;
var
  Body: String;
  JsonObj: TPHJson;
  SolicitacaoObj: TPHServerClass;
  Msg: String;
  SolicitacaoID: Int64;
begin
  Body := Trim(GetBody);

  JsonObj := TPHJson.Create;
  try
    JsonObj.LerJson(Body);
    SolicitacaoID := StrToInt(JsonObj.ElementoDoNome('SolicitacaoID').Texto);

    SolicitacaoObj := NewPHServerClass('SOLICITACOES');
    try
      IniciarTransacao;
      try
        SolicitacaoObj.CampoDoNome('ID').AsLargeInt := SolicitacaoID;
        SolicitacaoObj.LerRegistro;

        if (SolicitacaoObj.CampoDoNome('ID').AsLargeInt = 0) then
          ErroValidacao('Solicitacao nao encontrada para cancelamento.');

        SolicitacaoObj.CampoDoNome('SITUACAO').AsString := 'C';
        SolicitacaoObj.CampoDoNome('OBS').AsString := JsonObj.ElementoDoNome('Motivo').Texto;
        SolicitacaoObj.Salvar;

        ConfirmarTransacao;
        Msg := MontarRetornoSucesso('Solicitacao cancelada com sucesso.');
      except
        CancelarTransacao;
        Msg := MontarRetornoErro('Erro ao cancelar solicitacao: ' + ExceptionMessage);
      end;
    finally
      SolicitacaoObj.Free;
    end;
  finally
    JsonObj.Free;
  end;

  ParamByName('Result').AsString := Msg;
end;

begin
end.

Exemplo de Envio (cURL)

Cadastrar

curl -X POST "http://localhost:211/api/solicitacoes" ^
  -H "Content-Type: application/json" ^
  -H "Authorization: Bearer <access_token>" ^
  -d "{\"MetodoScript\":\"Cadastrar\",\"Cliente\":\"2\",\"Solicitante\":\"2\",\"TiposSolicitacao\":\"3\",\"Requisito\":\"2\",\"Prioridade\":\"2\",\"DescricaoResumida\":\"Solicitacao de exemplo\",\"Descricao\":\"Descricao detalhada\"}"

Consultar

curl -X POST "http://localhost:211/api/solicitacoes" ^
  -H "Content-Type: application/json" ^
  -H "Authorization: Bearer <access_token>" ^
  -d "{\"MetodoScript\":\"Consultar\",\"SolicitacaoID\":\"150\"}"

Cancelar

curl -X POST "http://localhost:211/api/solicitacoes" ^
  -H "Content-Type: application/json" ^
  -H "Authorization: Bearer <access_token>" ^
  -d "{\"MetodoScript\":\"Cancelar\",\"SolicitacaoID\":\"150\",\"Motivo\":\"Duplicidade\"}"

Resumo

Com esse padrao, um unico endpoint consegue atender varias operacoes de um mesmo dominio, mantendo:

  • Uma URL unica para integracao
  • Controle centralizado de autenticacao
  • Flexibilidade para evoluir os procedimentos no script

Para respostas personalizadas, utilize sempre:

ParamByName('Result').AsString := <texto ou JSON>;