A utilização do recurso de @annotations na linguagem TL++ possibilitou a simplificação da escrita para o desenvolvimento de API´s REST, mas ainda é possível desenvolver aplicações sem utilização deste recurso no modo tradicional, trataremos disto nesta documentação.
Inicialização de um serviço REST
Para poder utilizar aplicações REST sem o uso das @annotations, obrigatoriamente é necessário criar um serviço Http por meio de uma função fazendo uso de um objeto JSon. Veremos no exemplo abaixo como fazer isto:
User Function fInitService()
Local oVdrCtrl := VdrCtrl():New()
Local cAppPath := "/examples"
Local nResult := -1
Local jConfig
//Definição das configurações do HttpServer
jConfig['HTTPSERVER'] := JsonObject():New()
jConfig['HTTPSERVER']['Enable'] := .T.
jConfig['HTTPSERVER']['Log'] := .F.
jConfig['HTTPSERVER']['Charset'] := "ISO-8859-1"
jConfig['HTTPSERVER']['Servers'] := {"INIT_HTTP_REST"}
jConfig['INIT_HTTP_REST'] := JsonObject():New()
jConfig['INIT_HTTP_REST']['Port'] := "9995"
jConfig['INIT_HTTP_REST']['HostName'] := "TLPP_REST_SERVER"
jConfig['INIT_HTTP_REST']['ContentTypes'] := "ContentTypes"
jConfig['INIT_HTTP_REST']['Locations'] := {"HTTP_ROOT_01"}
jConfig['HTTP_ROOT_01'] := JsonObject():new()
jConfig['HTTP_ROOT_01']['Path'] := cAppPath
jConfig['HTTP_ROOT_01']['RootPath'] := "C:\tlppCore\bin\root\web"
jConfig['HTTP_ROOT_01']['DefaultPage'] := {"index.html"}
jConfig['HTTP_ROOT_01']['ThreadPool'] := "INIT_THREAD_POOL_01"
jConfig['INIT_THREAD_POOL_01'] := JsonObject():new()
jConfig['INIT_THREAD_POOL_01']['MinThreads'] := 1
jConfig['INIT_THREAD_POOL_01']['MaxThreads'] := 4
jConfig['INIT_THREAD_POOL_01']['MinFreeThreads'] := 1
jConfig['INIT_THREAD_POOL_01']['GrowthFactor'] := 1
jConfig['INIT_THREAD_POOL_01']['InactiveTimeout'] := 30000
jConfig['INIT_THREAD_POOL_01']['AcceptTimeout'] := 10000
jConfig['INIT_ContentTypes'] := JsonObject():new()
jConfig['INIT_ContentTypes']['htm'] := "text/html"
jConfig['INIT_ContentTypes']['html'] := "text/html"
jConfig['INIT_ContentTypes']['stm'] := "text/html"
jConfig['INIT_ContentTypes']['tsp'] := "text/html"
jConfig['INIT_ContentTypes']['js'] := "text/javascript"
jConfig['INIT_ContentTypes']['json'] := "text/plain;charset=ISO-8859-1"
jConfig['INIT_ContentTypes']['*'] := "application/octet-stream"
/* -----------------------------------------------------------
Aqui é feita a chamada para a função responsável por criar o
vinculo entre URN´s e as aplicações
----------------------------------------------------------- */
jConfig['INIT_HTTP_REST']['LoadURNs'] := JsonObject():new()
if !( sLoadURNs(@jConfig['INIT_HTTP_REST']['LoadURNs']) )
return Nil
endif
/*------------------------------------------------------------*/
nResult := oVdrCtrl:Start(jConfig)
if ( ValType(nResult) == 'N' .AND. nResult == 0 )
conout("### Servidor HTTP inicializado com sucesso!")
else
conout("### Erro ao iniciar HTTP Server - retorno [" + cValToChar(nResult) + "] - " + cValToChar(oVdrCtrl:getControlErrCode()) + " - " + oVdrCtrl:getControlErrDesc() )
endif
return nResult
OBS.: Caso já exista algum serviço REST sendo criado por meio de função utilizando-se um JSon, basta incluir a chamada da static sLoadUrn como será visto no item posterior.
Vinculando a URN à API
Como não está sendo utilizado o recurso das @annotations para poder desenvolver API´s REST, é preciso utilizar outra forma para efetuar o vínculo com a URN, isto é feito via função. A mesma é chamada do ponto destacado na função do item anterior, no exemplo citado está sendo feita a chamada para uma função do tipo Static, mas, nada impede que ela seja do tipo User, desde que respeitando o tipo de retorno e as regras de implementações que serão vistas no exemplo a seguir:
//Static Function responsável por criar o nó contendo o vínculo entre as URN´s e as API´s(funções) no objeto jSon que foi recebido como parametro e será utilizado no serviço REST que será executado a partir das definições do mesmo.
Static Function sLoadURNs(jEndpoints)
Local cDelPath := "/documentation/noannotation/delete"
Local cGetPath := "/documentation/noannotation/get"
Local cPatchPath := "/documentation/noannotation/patch"
Local cPostPath := "/documentation/noannotation/post"
Local cPutPath := "/documentation/noannotation/put"
if(ValType(jEndpoints) == 'U' .Or. ValType(jEndpoints) != 'J')
jEndpoints := jsonObject():New()
endIf
jEndpoints[cGetPath] := JsonObject():new()
jEndpoints[cGetPath]['GET'] := JsonObject():new()
jEndpoints[cGetPath]['GET']['ClassName'] := ""
jEndpoints[cGetPath]['GET']['Function'] := "U_getExampleNoAnnotation"
jEndpoints[cGetPath]['GET']['EndPoint'] :={"documentation", "noannotation", "get"}
jEndpoints[cDelPath]['DELETE'] := JsonObject():new()
jEndpoints[cDelPath]['DELETE']['ClassName'] := ""
jEndpoints[cDelPath]['DELETE']['Function'] := "U_deleteExampleNoAnnotation"
jEndpoints[cDelPath]['DELETE']['EndPoint'] :={"documentation", "noannotation", "delete"}
jEndpoints[cPatchPath]['PATCH'] := JsonObject():new()
jEndpoints[cPatchPath]['PATCH']['ClassName'] := ""
jEndpoints[cPatchPath]['PATCH']['Function'] := "U_patchExampleNoAnnotation"
jEndpoints[cPatchPath]['PATCH']['EndPoint'] :={"documentation", "noannotation", "patch"}
jEndpoints[cPostPath]['POST'] := JsonObject():new()
jEndpoints[cPostPath]['POST']['ClassName'] := ""
jEndpoints[cPostPath]['POST']['Function'] := "U_postExampleNoAnnotation"
jEndpoints[cPostPath]['POST']['EndPoint'] :={"documentation", "noannotation", "post"}
jEndpoints[cPutPath]['PUT'] := JsonObject():new()
jEndpoints[cPutPath]['PUT']['ClassName'] := ""
jEndpoints[cPutPath]['PUT']['Function'] := "U_putExampleNoAnnotation"
jEndpoints[cPutPath]['PUT']['EndPoint'] :={"documentation", "noannotation", "put"}
Return .T.
OBSERVAÇÃO
As funções, os endpointsconfigurações