-
Notifications
You must be signed in to change notification settings - Fork 13
/
07.tarefas.apw
183 lines (161 loc) · 7.31 KB
/
07.tarefas.apw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#include 'protheus.ch'
#include 'restful.ch'
// Nome da tabela do sistema que utilizaremos
#define TABELA_TAREFAS "tarefas"
// Preparamos a base de dados para nosso CRUD
// Utilizaremos o driver SQLite do sistema disponível a partir do Protheus 12
// Invoque `U_TAREFAS` antes de começar a fazer as requisições para preparar a
// tabela
User Function Tarefas()
Local aStruct := {}
AAdd( aStruct, { "CONTEUDO", "C", 128, 0 } ) // Conteúdo da tarefa
AAdd( aStruct, { "DT_CRIACAO", "C", 8, 0 } ) // Data que foi criada
AAdd( aStruct, { "HR_CRIACAO", "C", 8, 0 } ) // Hora que foi criada
AAdd( aStruct, { "DT_COMPLET", "C", 8, 0 } ) // Data que foi completada
AAdd( aStruct, { "HR_COMPLET", "C", 8, 0 } ) // Hora que foi completada
DbCreate( TABELA_TAREFAS, aStruct, "SQLITE_SYS" )
Return
WsRestful Tarefas Description "Gerenciador de tarefas" Format APPLICATION_JSON
// ID de uma tarefa. O `As Integer` já injeta o parâmetro como um numérico
// do AdvPL para a gente, sem a necessidade de usar `Val`!
WsData Id As Integer Optional
// Métodos e suas rotas
// Você pode ter quantos `WsMethod` forem necessários, desde que a chave
// seja único por verbo + id. da ação
//
// (verbo) (Id. da ação) (descrição documentativa) (rota real da requisição)
// | | |__________. |
// V V V V
WsMethod GET ListarTarefas Description "Listar tarefas" Path "/tarefas"
WsMethod POST CriarTarefa Description "Criar tarefa" Path "/tarefa"
WsMethod PUT AtualizarTarefa Description "Atualizar tarefa" Path "/tarefa/{id}"
WsMethod DELETE ApagarTarefa Description "Apagar tarefa" Path "/tarefa/{id}"
End WsRestful
// [GET /tarefas] - listar todas as tarefas
// Retorna um JSON como array de objetos com as informações de cada tarefa
WsMethod GET ListarTarefas WsRestful Tarefas
// Array de retorno
Local aRetorno := {}
// Alias de tabela SQLite
Local cTarefas := GetNextAlias()
Local oTarefa
// Abrimos a tabela de tarefas e percorremos os registros
DbUseArea( .T., "SQLITE_SYS", TABELA_TAREFAS, cTarefas, .T., .T. )
DbSelectArea( cTarefas )
Do While !( cTarefas )->( Eof() )
// Criamos um objeto JSON para cada registro
// Usaremos o número do registro como ID
// Devolveremos a data e hora de criação em um formato ISO padrão
// Uma tarefa está completada se há registro de data que ela foi completada
// Devolvemos o conteúdo sem espaços sobrando
oTarefa := JsonObject():New()
oTarefa[ "id" ] := ( cTarefas )->( RecNo() )
oTarefa[ "criada_em" ] := FWTimeStamp( 3, SToD( ( cTarefas )->DT_CRIACAO ), ( cTarefas )->HR_CRIACAO )
oTarefa[ "completada" ] := !Empty( ( cTarefas )->DT_COMPLET )
oTarefa[ "conteudo" ] := AllTrim( ( cTarefas )->CONTEUDO )
// Adicionamos cada objeto JSON ao retorno e vamos para o próximo registro
AAdd( aRetorno, oTarefa )
( cTarefas )->( DbSkip() )
EndDo
// Fechamos a área de trabalho de tarefas e devolvemos a lista de tarefas
( cTarefas )->( DbCloseArea() )
::SetResponse( FWJsonSerialize( aRetorno ) )
Return .T.
// [POST /tarefa] - criar uma tarefa
// Deve receber no corpo da requisição JSON no formato `{ "conteudo": "..." }`
WsMethod POST CriarTarefa WsRestful Tarefas
Local oJson := JsonObject():New()
Local oRetorno
Local cTarefas
Local cData
Local cHora
// `oJson` irá carregar os dados vindos do corpo da requisição
oJson:FromJson( ::GetContent() )
// Se o conteúdo não for informado, é um `BAD REQUEST`
If Empty( oJson[ "conteudo" ] )
SetRestFault( 400, "É necessário informar o conteúdo" )
Return .F.
EndIf
// Abrimos a tabela de tarefas, computamos em strings a data e hora atuais
// e gravamos o registro com bloqueio
cTarefas := GetNextAlias()
cData := DToS( Date() )
cHora := Time()
DbUseArea( .T., "SQLITE_SYS", TABELA_TAREFAS, cTarefas )
DbSelectArea( cTarefas )
( cTarefas )->( DbAppend( .F. ) )
( cTarefas )->CONTEUDO := oJson[ "conteudo" ]
( cTarefas )->DT_CRIACAO := cData
( cTarefas )->HR_CRIACAO := cHora
( cTarefas )->( DbCommit() )
// É idiomático em REST retornarmos as informações do registro criado
oRetorno := JsonObject():New()
oRetorno[ "id" ] := ( cTarefas )->( RecNo() )
oRetorno[ "conteudo" ] := oJson[ "conteudo" ]
oRetorno[ "criada_em" ] := FWTimeStamp( 3, SToD( cData ), cHora )
oRetorno[ "completada" ] := .F.
// Iremos responder com um JSON com o retorno serializado em JSON
// Também definimos o status HTTP como 201, isto é, `CREATED`
( cTarefas )->( DbCloseArea() )
::SetStatus( 201 )
::SetContentType( APPLICATION_JSON )
::SetResponse( FWJsonSerialize( oRetorno ) )
// Hora de liberar memória
FreeObj( oJson )
FreeObj( oRetorno )
Return .T.
// [PUT /tarefa/{id}] - atualiza uma tarefa pelo ID
// O formato do corpo da requisição é o mesmo do de criação
WsMethod PUT AtualizarTarefa PathParam Id WsRestful Tarefas
Local oJson := JsonObject():New()
Local oRetorno
Local cTarefas
Local cData
Local cHora
// `oJson` irá carregar os dados vindos do corpo da requisição
oJson:FromJson( ::GetContent() )
// Se o conteúdo não for informado, é um `BAD REQUEST`
If Empty( oJson[ "conteudo" ] )
SetRestFault( 400, "É necessário informar o conteúdo" )
Return .F.
EndIf
// Abrimos a tabela de tarefas e atualizamos o conteúdo
cTarefas := GetNextAlias()
DbUseArea( .T., "SQLITE_SYS", TABELA_TAREFAS, cTarefas )
DbSelectArea( cTarefas )
( cTarefas )->( DbRLock() )
( cTarefas )->CONTEUDO := oJson[ "conteudo" ]
( cTarefas )->( DbCommit() )
( cTarefas )->( DbUnlock() )
// É idiomático em REST retornarmos as informações do registro atualizado
oRetorno := JsonObject():New()
oRetorno[ "id" ] := ( cTarefas )->( RecNo() )
oRetorno[ "criada_em" ] := FWTimeStamp( 3, SToD( ( cTarefas )->DT_CRIACAO ), ( cTarefas )->HR_CRIACAO )
oRetorno[ "completada" ] := !Empty( ( cTarefas )->DT_COMPLET )
oRetorno[ "conteudo" ] := AllTrim( ( cTarefas )->CONTEUDO )
// Iremos responder com um JSON com o retorno serializado em JSON
( cTarefas )->( DbCloseArea() )
::SetContentType( APPLICATION_JSON )
::SetResponse( FWJsonSerialize( oRetorno ) )
// Hora de liberar memória
FreeObj( oJson )
FreeObj( oRetorno )
Return .T.
// [DELETE /tarefa/{id}] - apaga uma tarefa pelo ID
// Retorna erro 404 se a tarefa não existir
WsMethod DELETE ApagarTarefa PathParam Id WsRestful Tarefas
Local cTarefas := GetNextAlias()
// Abrimos a tabela de tarefas e tentamos posicionar no registro passado
DbUseArea( .T., "SQLITE_SYS", TABELA_TAREFAS, cTarefas )
DbSelectArea( cTarefas )
( cTarefas )->( dbGoTo( ::Id ) )
If ( cTarefas )->( Eof() )
// Fim de arquivo indica que a tarefa não existe
SetRestFault( 404, "Tarefa não encontrada" )
Return .F.
EndIf
// Travamos o registro, deletamos e liberamos o bloqueio
( cTarefas )->( DbRLock() )
( cTarefas )->( DbDelete() )
( cTarefas )->( DbCloseArea() )
Return .T.