Integracao REST end-to-end com TLPP

Tutorial: criar endpoint REST em TLPP, consumir API externa, autenticacao com token, error handling. Caso de uso real de integracao.

Vamos criar uma integracao real: um endpoint REST em TLPP que recebe pedido, consulta servico externo de credito, e responde com aprovado/recusado. Cobre 90% das integracoes do dia-a-dia.

1. Habilitar HTTP no appserver.ini

[HTTPV11]
ENABLE=1
PORT=8080
INSTANCES=1,2
INSTANCENAME=APIREST

2. Escrever o endpoint TLPP

#include 'tlpp-core.th'
#include 'tlpp-rest.th'

namespace archtec.api

@Post('/v1/pedidos/validar')
function ValidaPedido()
    local cBody     as character
    local oReq      as object
    local oResp     as object
    local cToken    as character
    local lOk       as logical

    // 1. Autenticacao
    cToken := httpRequest:getHeader('Authorization')
    if !ValidaToken(cToken)
        httpResponse:setStatus(401)
        httpResponse:setBody('{"error":"unauthorized"}')
        return
    endif

    // 2. Parse do body
    try
        cBody := httpRequest:getBody()
        oReq  := JsonObject():new()
        oReq:fromJson(cBody)
    catch tExceptionError oErr
        httpResponse:setStatus(400)
        httpResponse:setBody('{"error":"invalid_json"}')
        return
    endtry

    // 3. Logica de negocio (consulta credito externo)
    oResp := JsonObject():new()
    oResp['cliente']    := oReq['cliente']
    oResp['aprovado']   := ConsultaCredito(oReq['cliente'], oReq['valor'])
    oResp['timestamp']  := DToS(Date()) + Time()
    oResp['tx_id']      := FwUuidV4()

    // 4. Responder
    httpResponse:setStatus(200)
    httpResponse:setContentType('application/json')
    httpResponse:setBody(oResp:toJson())
return

3. Validador de token

static function ValidaToken(cAuth as character) as logical
    local cToken as character

    if !'Bearer ' $ cAuth
        return .F.
    endif

    cToken := substr(cAuth, 8)
    // Verifica contra tabela ZAP (api keys)
return !empty(Posicione('ZAP', 1, xFilial('ZAP') + cToken, 'ZAP_COD'))

4. Cliente HTTP pra consultar API externa

static function ConsultaCredito(cCliente as character, nValor as numeric) as logical
    local oClient  as object
    local oResp    as object
    local cBody    as character

    oClient := FwHttpClient():new('https://credito-externo.com/api/check')
    oClient:setHeader('Authorization', 'Bearer ' + GetMv('MV_CREDIT_KEY', .F., ''))
    oClient:setHeader('Content-Type', 'application/json')
    oClient:setBody('{"doc":"' + cCliente + '","valor":' + cValToChar(nValor) + '}')
    oClient:setSocketTimeout(10000)  // 10s

    try
        if oClient:post()
            cBody := oClient:getHTTPResponse():getHTTPResponse()
            oResp := JsonObject():new()
            oResp:fromJson(cBody)
            return oResp['status'] == 'approved'
        endif
    catch tExceptionError oErr
        FwLogger():getLogger():error('Credito API: ' + oErr:getDescription())
    endtry
return .F.  // falha = nao aprovado

5. Testar com curl

curl -X POST http://localhost:8080/v1/pedidos/validar \
     -H 'Authorization: Bearer SEU_TOKEN' \
     -H 'Content-Type: application/json' \
     -d '{"cliente":"00000000000191","valor":15000}'

# Esperado:
# {"cliente":"00000000000191","aprovado":true,"timestamp":"...","tx_id":"..."}

6. Pegadinhas de producao

Veja também