Exemplo de Endpoint para Execução de Múltiplos Procedimentos Com PHSYS API

Introdução

Este exemplo mostra como configurar um único endpoint de API para executar vários procedimentos internos, usando o campo MetodoScript no body da requisição.

A proposta é ter um endpoint único, por exemplo:

http://localhost:211/api/solicitacoes

e dentro do script, direcionar a execução para:

  • Cadastrar
  • Consultar
  • Cancelar

Esse modelo é útil quando os procedimentos pertencem ao mesmo contexto funcional e compartilham a mesma autenticação e URL de integração.

Modelo de Integração Personalizado

No cadastro do endpoint no PHServerConf:

  • Modelo de integração: Personalizado
  • Classe: script específico
  • Procedimento: GetMetodo
  • Exige token: Sim (opcional, recomendado)

Com isso, toda requisição ao endpoint passa pelo procedimento GetMetodo, que decide qual ação executar com base no body.

Cabeçalhos Necessários

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

Estrutura da Requisição

URL:

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

Método HTTP:

POST

Body base:

{
  "MetodoScript": "Cadastrar | Consultar | Cancelar",
  "...": "demais campos conforme cada método"
}

Exemplos de Body

Cadastrar

{
  "MetodoScript": "Cadastrar",
  "Cliente": "2",
  "Solicitante": "2",
  "TiposSolicitacao": "3",
  "Requisito": "2",
  "Prioridade": "2",
  "DescricaoResumida": "Solicitação de exemplo",
  "Descricao": "Descrição detalhada da solicitação"
}

Consultar

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

Cancelar

{
  "MetodoScript": "Cancelar",
  "SolicitacaoID": "150",
  "Motivo": "Solicitação 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 inválido. Método informado: ' + Metodo);
end;

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

  if (Body = '') then
    ErroValidacao('Faltou informar o body da requisição.');

  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":"Solicitação cadastrada.",' +
            '"SolicitacaoID":"' + IntToStr(SolicitacaoObj.CampoDoNome('ID').AsLargeInt) + '"' +
          '}';
      except
        CancelarTransacao;
        Msg := MontarRetornoErro('Erro ao cadastrar solicitação: ' + 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('Solicitação não 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('Solicitação não encontrada para cancelamento.');

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

        ConfirmarTransacao;
        Msg := MontarRetornoSucesso('Solicitação cancelada com sucesso.');
      except
        CancelarTransacao;
        Msg := MontarRetornoErro('Erro ao cancelar solicitação: ' + 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\":\"Solicitação de exemplo\",\"Descricao\":\"Descrição 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\"}"

Conclusão

Com esse padrão, um único endpoint consegue atender várias operações de um mesmo domínio, mantendo:

  • Uma URL única para integração
  • Controle centralizado de autenticação
  • Flexibilidade para evoluir os procedimentos no script

Para respostas personalizadas, utilize sempre:

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