{"id":502,"date":"2024-04-14T23:51:46","date_gmt":"2024-04-15T02:51:46","guid":{"rendered":"https:\/\/adrianosantostreina.com.br\/blog\/?p=502"},"modified":"2024-04-22T09:51:24","modified_gmt":"2024-04-22T12:51:24","slug":"documentando-a-api-horse-no-delphi-com-swager","status":"publish","type":"post","link":"https:\/\/adrianosantostreina.com.br\/blog\/documentando-a-api-horse-no-delphi-com-swager\/","title":{"rendered":"Documentando a API Horse no Delphi com Swagger"},"content":{"rendered":"\n<p>A documenta\u00e7\u00e3o \u00e9 um componente essencial no desenvolvimento de APIs, facilitando tanto para os desenvolvedores que criam a API quanto para aqueles que a consomem. Uma ferramenta amplamente reconhecida para essa finalidade \u00e9 o Swagger, que permite descrever a estrutura de suas APIs para que possam ser compreendidas e utilizadas por um p\u00fablico amplo. Neste artigo, exploraremos como implementar o Swagger em uma API Delphi usando o framework Horse e o middleware GBSwagger.<\/p>\n\n\n\n<!--more-->\n\n\n\n<h2 class=\"wp-block-heading\"><\/h2>\n\n\n\n<p class=\"has-large-font-size\"><strong>O que \u00e9 Swagger?<\/strong><\/p>\n\n\n\n<p>Swagger \u00e9 uma especifica\u00e7\u00e3o e um conjunto de ferramentas de software para descrever, produzir, consumir e visualizar servi\u00e7os web RESTful. Ele oferece um formato padr\u00e3o para a descri\u00e7\u00e3o de uma API, incluindo rotas, m\u00e9todos de requisi\u00e7\u00e3o, par\u00e2metros de entrada, formatos de resposta, e muito mais. Al\u00e9m disso, o Swagger inclui uma interface de usu\u00e1rio web que permite aos desenvolvedores interagir com a API diretamente atrav\u00e9s do navegador, facilitando o teste e a integra\u00e7\u00e3o.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><\/h2>\n\n\n\n<p class=\"has-large-font-size\"><strong>Vantagens de documentar a API<\/strong><\/p>\n\n\n\n<p>Documentar uma API tem v\u00e1rias vantagens significativas:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Claridade operacional:<\/strong> Ajuda os desenvolvedores a entenderem rapidamente como a API funciona, quais servi\u00e7os oferece e como integr\u00e1-la.<\/li>\n\n\n\n<li><strong>Facilidade de integra\u00e7\u00e3o:<\/strong> Consumidores da API podem testar os endpoints diretamente e ver como os sistemas respondem em tempo real.<\/li>\n\n\n\n<li><strong>Redu\u00e7\u00e3o de tempo de integra\u00e7\u00e3o:<\/strong> Reduz o tempo necess\u00e1rio para que novos desenvolvedores se familiarizem com a API.<\/li>\n\n\n\n<li><strong>Maior ades\u00e3o e uso:<\/strong> Uma boa documenta\u00e7\u00e3o pode aumentar a utiliza\u00e7\u00e3o da API, uma vez que \u00e9 mais f\u00e1cil de usar e entender.<\/li>\n\n\n\n<li><strong>Feedback e melhorias:<\/strong> A documenta\u00e7\u00e3o clara permite que os usu\u00e1rios finais forne\u00e7am feedback mais construtivo para melhorar a API.<\/li>\n<\/ul>\n\n\n\n<p>Como podemos ver, o Swagger \u00e9 essencial para que a API seja entendida na sua completude. Al\u00e9m disso, o Swagger \u00e9 fortemente usando no mercado para documentar API&#8217;s em diversas linguagens de programa\u00e7\u00e3o. Voc\u00ea pode, obviamente, criar sua documenta\u00e7\u00e3o da forma como desejar, mas saiba que desenvolvedores Delphi ou de outras linguagens est\u00e3o muito acostumados ao formato do Swagger. Outro ponto importante \u00e9 que voc\u00ea pode simplesmente abrir um editor de c\u00f3digo fonte como VSCode, SublimeText ou at\u00e9 bloco de notas como o Notepadd++ e criar sua documenta\u00e7\u00e3o Swagger, entretanto o desafio aqui \u00e9 criar a api ao mesmo tempo que documentamos ela, vamos l\u00e1?<\/p>\n\n\n\n<p class=\"has-large-font-size\"><strong>Iniciando no GBSwagger<\/strong><\/p>\n\n\n\n<p>O desenvolvimento de apis no Delphi pode ser feito com diversos frameworks, nesse artigo veremos um exemplo com o Horse que j\u00e1 possui um middleware de terceiro para documentar usando Swagger. Vamos usar o GBSwagger do meu amigo Gabriel Baltazar. Ele se integra facilmente ao Horse e permite que a gente crie a API no mesmo momento que a documenta.<\/p>\n\n\n\n<p class=\"has-medium-font-size\"><strong>Exemplo:<\/strong><\/p>\n\n\n\n<p>Vamos criar um exemplo muito simples para que entenda como tudo funciona. Imagine uma API que ir\u00e1 listar uma tabela de Clientes de um banco de dados qualquer. Essa tabela ter\u00e1 apenas os campos:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ID : Integer;\nNome: string;\nDataDeInclusao : TDateTime;\nCreditoPreAprovado: Double;\nDiasPraPagar: Integer;<\/code><\/pre>\n\n\n\n<p>Algo bem simples como pudemos ver. N\u00e3o vamos fazer conex\u00e3o com banco de dados, t\u00e3o pouco as opera\u00e7\u00f5es de CRUD, o objetivo aqui \u00e9 s\u00f3 criar a documenta\u00e7\u00e3o.<br><\/p>\n\n\n\n<p>Crie ent\u00e3o um projeto novo, d\u00ea um nome a ele e fa\u00e7a a instala\u00e7\u00e3o do Horse juntamente com o middlware Jhonson. N\u00e3o entrarei em detalhes, pois suponho nesse artigo que voc\u00ea j\u00e1 esteja familiarizado com o Horse.<\/p>\n\n\n\n<p><strong>Instalando o GBSwagger<\/strong><\/p>\n\n\n\n<p>A instala\u00e7\u00e3o do GBSwagger \u00e9 bem f\u00e1cil assim como qualquer outro middleware. Ele est\u00e1 listado entre os middlewares de terceiro na p\u00e1gina do GitHub da HashLoad, time que desenvolve o Horse. Basta acessar o link do GBSwagger na p\u00e1gina ou pra facilitar <a href=\"https:\/\/github.com\/gabrielbaltazar\/gbswagger\" target=\"_blank\" rel=\"noreferrer noopener\">clique aqui<\/a>. Recomendo fortemente que leia a documenta\u00e7\u00e3o, \u00e9 bem simples, mas tem detalhes que s\u00e3o importantes para composi\u00e7\u00e3o da sua documenta\u00e7\u00e3o.<\/p>\n\n\n\n<p>Uma vez sua api criada, basta acessar o terminal no Windows, navegar at\u00e9 a pasta do projeto e digitar:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \" >boss install github.com\/gabrielbaltazar\/gbswagger<\/pre><\/div>\n\n\n\n<p>Caso n\u00e3o use o Boss para gerenciar suas depend\u00eancias, baixe o projeto GBSwagger para o computador, descompacte a pasta em um local da sua prefer\u00eancia e adicione a refer\u00eancia da pasta no Library Path do projeto.<\/p>\n\n\n\n<p class=\"has-large-font-size\"><strong>Uso do GBSwagger<\/strong><\/p>\n\n\n\n<p>Assim como qualquer outro middleware, basta adicionarmos a unit do projeto, nesse caso Horse.GBSwagger ao uses e ent\u00e3o adicionar a linha abaixo no DPR da aplica\u00e7\u00e3o.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \" >THorse\n  .Use(HorseSwagger); \/\/ Access http:\/\/localhost:9000\/swagger\/doc\/html<\/pre><\/div>\n\n\n\n<p>Copiamos a linha de exemplo do GitHub do GBSwagger, perceba que o caminho default da documenta\u00e7\u00e3o est\u00e1 comentada no pr\u00f3prio exemplo. Essa \u00e9 uma das principais vantagens do middleware. Quando constru\u00edmos a documenta\u00e7\u00e3o de qualquer api \u00e9 comum criarmos o arquivo HTML dessa documenta\u00e7\u00e3o e publicarmos em um servi\u00e7o de hospedagem para que fique vis\u00edvel, no caso do Horse e do GBSwagger, a documenta\u00e7\u00e3o acompanha o execut\u00e1vel da API. Isso mesmo! Em qualquer lugar que voc\u00ea publicar a API a documenta\u00e7\u00e3o j\u00e1 estar\u00e1 pronta. Legal n\u00e9?<\/p>\n\n\n\n<p>H\u00e1 uma variante do .Use, \u00e9 poss\u00edvel voc\u00ea especificar o caminho onde essa documenta\u00e7\u00e3o ser\u00e1 apresentada. Por exemplo:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \" >[...]\nTHorse\n  .Use(HorseSwagger(Format('%s\/swagger\/doc\/html', ['v1']),Format('%s\/swagger\/doc\/json', ['v1'])));\n[...]<\/pre><\/div>\n\n\n\n<p>No exemplo acima especifiquei que a documenta\u00e7\u00e3o ser\u00e1 acess\u00edvel no link <strong><em>http:\/\/localhost:9000\/v1\/swagger\/doc\/html<\/em><\/strong>, ou seja, podemos personalizar o endere\u00e7o como desejarmos. Vamos manter esse padr\u00e3o com o &#8220;v1&#8221; para simular uma vers\u00e3o de nossa API. O c\u00f3digo completo do DPR desse exemplo simples ficou assim:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \" >program MinhaAPI;\n\n{$APPTYPE CONSOLE}\n\n{$R *.res}\n\nuses\n  Horse,\n  Horse.Jhonson,\n  Horse.GBSwagger,\n  System.SysUtils,\n  API.Controller.Clientes in 'controllers\\API.Controller.Clientes.pas',\n  API.Model.Clientes in 'model\\API.Model.Clientes.pas';\n\nbegin\n  THorse\n    .Use(Jhonson);\n\n  THorse\n    .Use(HorseSwagger(Format('%s\/swagger\/doc\/html', ['v1']),Format('%s\/swagger\/doc\/json', ['v1'])));\n\n  THorse\n    .Group\n      .Prefix('v1')\n        .get('ping',\n        procedure(Req: THorseRequest; Res: THorseResponse)\n        begin\n          Res.Send('pong')\n        end\n        );\n\n  THorse\n    .Listen(9000);\nend.<\/pre><\/div>\n\n\n\n<p>Uma vez feita a primeira configura\u00e7\u00e3o do Swagger, se executarmos nossa api e abrirmos o browser com o endere\u00e7o dessa documenta\u00e7\u00e3o, veremos algo semelhante a figura abaixo:<br><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img fetchpriority=\"high\" decoding=\"async\" width=\"1024\" height=\"764\" src=\"https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-9-1024x764.png\" alt=\"\" class=\"wp-image-510\" srcset=\"https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-9-1024x764.png 1024w, https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-9-300x224.png 300w, https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-9-768x573.png 768w, https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-9.png 1093w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"has-large-font-size\"><strong>Entendendo a Documenta\u00e7\u00e3o<\/strong><\/p>\n\n\n\n<p>J\u00e1 temos aqui algumas informa\u00e7\u00f5es. Com o middleware <strong>GBSwagger <\/strong>configurado, voc\u00ea pode come\u00e7ar a documentar sua API. O primeiro passo \u00e9 definir o cabe\u00e7alho da documenta\u00e7\u00e3o, que inclui informa\u00e7\u00f5es b\u00e1sicas como o t\u00edtulo da API, uma breve descri\u00e7\u00e3o, a vers\u00e3o e os termos de servi\u00e7o. Eu gosto de deixar meus projetos bem separados em units, cada uma com sua responsabilidade. Por isso, crie uma nova unit no Delphi, chame-a de <strong>API.Swagger.Doc<\/strong> e escreva o seu c\u00f3digo como abaixo:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \" >unit API.Swagger.Doc;\n\n\n\ninterface\n\nuses\n  Horse.GBSwagger;\n\nprocedure StartDocumentation;\n\nimplementation\n\nprocedure StartDocumentation;\nbegin\n  Swagger\n      .Info\n        .Title('API de Clientes - Adriano Santos Blog')\n        .Description('API de exemplo para artigo')\n        .Contact\n          .Name('Adriano Santos')\n          .Email('adriano@adrianosantostreina.com.br')\n          .URL('https:\/\/adrianosantostreina.com.br')\n        .&amp;End\n      .&amp;end;\n  Swagger\n    .Config\n      .ClassPrefixes('TModel')\n    .&amp;End;\nend;\n\ninitialization\n  StartDocumentation;\n\nend.<\/pre><\/div>\n\n\n\n<p>O que fizemos aqui \u00e9 relativamente simples. Criamos uma procedure que inicializar\u00e1 o cabe\u00e7alho da documenta\u00e7\u00e3o, implementamos nossas personaliza\u00e7\u00f5es e chamamos essa procedure pelo Initialization da unit. Bem f\u00e1cil. Se voc\u00ea abrir agora a documenta\u00e7\u00e3o ela se parecer\u00e1 com a figura a seguir:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" width=\"1024\" height=\"764\" src=\"https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-10-1024x764.png\" alt=\"\" class=\"wp-image-513\" srcset=\"https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-10-1024x764.png 1024w, https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-10-300x224.png 300w, https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-10-768x573.png 768w, https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-10.png 1093w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>J\u00e1 mudou bastante e por ai vai. Podemos personalizar muitas coisas. Eu recomendo que d\u00ea um Ctrl + Barra de Espa\u00e7o nas se\u00e7\u00f5es e veja o que pode ser personalizado. <\/p>\n\n\n\n<p class=\"has-large-font-size\"><strong>Incluindo os Endpoints e Verbos<\/strong><\/p>\n\n\n\n<p>Bom, at\u00e9 o momento temos apenas o cabe\u00e7alho da documenta\u00e7\u00e3o. Vamos exemplificar a cria\u00e7\u00e3o dos endepoints para GET, POST, PUT e DELETE da nossa api. Mas antes, deixa eu fazer um par\u00eanteses e explicar outras vantagens do middleware.<\/p>\n\n\n\n<p><strong>Registro das Rotas<\/strong><\/p>\n\n\n\n<p>Se voc\u00ea j\u00e1 est\u00e1 acostumado a criar API em Horse, vai lembrar que para registrar uma rota podemos simplesmente chamar a classe THorse e passar o verbo com a procedure an\u00f4nima associada \u00e0s implementa\u00e7\u00f5es do endpoint, assim:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \" >[...]\n\nTHorse\n  .Get('clientes', \n  procedure (Req: THorseRequest;Res: THorseResponse)\n  begin\n    \/\/Seu c\u00f3digo aqui\n  end\n  )\n\n[...]<\/pre><\/div>\n\n\n\n<p>Do mesmo modo podemos implementar os demais verbos. O GBSwagger possui classes e m\u00e9todos que j\u00e1 fazem o registro da rota automaticamente e fica muito mais f\u00e1cil trabalhar, assim, podemos criar a api e j\u00e1 documentar em uma &#8220;paulada&#8221; s\u00f3. Para isso, precisamos tomar apenas uma \u00fanica provid\u00eancia: transformar nossos Controllers em classes. Eu gosto de usar <em><strong>TControllerNOME_DO_RECURSO<\/strong><\/em>, exemplo: <strong>TControllerClientes<\/strong>, <strong>TControllerFornecedores<\/strong>, e assim sucessivamente. Mas fica a seu crit\u00e9rio. <\/p>\n\n\n\n<p class=\"has-large-font-size\"><strong>Criando o primeiro controller com o GBSwagger<\/strong><\/p>\n\n\n\n<p>Perfeito, ent\u00e3o vamos criar uma controller para a tabela de Clientes. Crie uma unit nova no Delphi, salve como <strong>API.Controller.Clientes<\/strong> e escreva o c\u00f3digo dela como abaixo.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \" >unit API.Controller.Clientes;\n\ninterface\n\nuses\n  Horse,\n\n  System.StrUtils,\n  System.SysUtils,\n  System.Classes,\n\n  Horse.GBSwagger.Register,\n  Horse.GBSwagger.Controller,\n  GBSwagger.Path.Attributes,\n\n  API.Model.Clientes;\n\ntype\n  [SwagPath('v1', 'clientes')]\n  TControllerClientes = class(THorseGBSwagger)\n  private\n\n  public\n    [SwagGet('clientes', 'Descri\u00e7\u00e3o do Endpoint')]\n    [SwagResponse(200, TModelClientes, 'Retorno com sucesso')]\n    procedure DoListClientes;\n  end;\n\n\nimplementation\n\n{ TControllerClientes }\n\nprocedure TControllerClientes.DoListClientes;\nbegin\n  FResponse.Send('JSON da Lista de Clientes');\nend;\n\ninitialization\n\nTHorseGBSwaggerRegister.RegisterPath(TControllerClientes);\n\nend.\n<\/pre><\/div>\n\n\n\n<p>Vou te explicar o que fizemos aqui. Declaramos todas as units necess\u00e1rias do Horse e GBSwagger e criamos uma classe chamada TControllerClientes. Perceba que antes da classe temos uma anota\u00e7\u00e3o. Essa anota\u00e7\u00e3o criar\u00e1 na documenta\u00e7\u00e3o uma TAG chamada Clientes com o prefixo &#8216;v1&#8217;, isso significa que nosso endpoint de clientes ficar\u00e1 <strong><em>http:\/\/localhost:9000\/v1\/clientes<\/em><\/strong>. Tamb\u00e9m informamos que a classe ser\u00e1 herdada de <strong>THorseGBSwagger<\/strong>, essa classe do GBSwagger j\u00e1 tem algumas coisas que precisamos pra registrar a rota.<\/p>\n\n\n\n<p>Em seguida, criamos o m\u00e9todo que responder\u00e1 quando a rota for requisitada. Veja que temos outra anota\u00e7\u00e3o acima do m\u00e9todo <strong>DoListClientes<\/strong>. <\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \" >    [SwagGet('clientes', 'Descri\u00e7\u00e3o do Endpoint')]\n    [SwagResponse(200, TModelClientes, 'Retorno com sucesso')]<\/pre><\/div>\n\n\n\n<p>Na verdade temos duas anota\u00e7\u00f5es, <strong>SwagGet <\/strong>e <strong>SwagResponse<\/strong>. A primeira determina que o verbo desse endpoint ser\u00e1 do tipo <strong>Get <\/strong>e a segunda informa que temos um retorno do tipo <strong>200 <\/strong>que ser\u00e1 o retorno default. Podemos incluir outros retornos, quantos quisermos. <\/p>\n\n\n\n<p>Outro detalhe, voc\u00ea notar\u00e1 que em <strong>SwagResponse <\/strong>temos um segundo par\u00e2metro apontando para a classe <strong>TModelClientes<\/strong>. Esse par\u00e2metro representa o <strong>Schema <\/strong>do endpoint, ou seja, o que ser\u00e1 retornado. Voc\u00ea pode simplesmente colocar uma string ou criar uma classe que represente os campos da tabela que ser\u00e3o retornados, essa parte \u00e9 a que mais gosto. <\/p>\n\n\n\n<p>Antes de continuarmos, crie uma nova unit, salve como<strong> API.Model.Clientes<\/strong> e digite o c\u00f3digo abaixo:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \" >unit API.Model.Clientes;\n\ninterface\n\nuses\n  GBSwagger.Model.Attributes;\n\ntype\n  TModelClientes = class\n  private\n    FID : Integer;\n    FNome: string;\n    FDataDeInclusao : TDateTime;\n    FCreditoPreAprovado: Double;\n    FDiasPraPagar: Integer;\n  public\n    property ID : Integer read FID write FID;\n    property Nome: string read FNome write FNome;\n    property DataDeInclusao : TDateTime read FDataDeInclusao write FDataDeInclusao;\n    property CreditoPreAprovado: Double read FCreditoPreAprovado write FCreditoPreAprovado;\n    property DiasPraPagar: Integer read FDiasPraPagar write FDiasPraPagar;\n  end;\n\nimplementation\n\nend.<\/pre><\/div>\n\n\n\n<p>N\u00e3o precisa necessariamente ter esse nome de Unit nem de Classe, crie como desejar. Eu prefiro dessa forma, creio que fique mais claro. Perceba que n\u00e3o tem nada demais ai, apenas uma classe com as propriedades que v\u00e3o representar cada campo. N\u00f3s voltaremos nela mais adiante.<\/p>\n\n\n\n<p>Retorne para a unit do <strong>Controller <\/strong>e ao final da unit n\u00e3o podemos esquecer de chamar o registro da classe que por sua vez vai registrar a rota.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \" >initialization\n\nTHorseGBSwaggerRegister.RegisterPath(TControllerClientes);<\/pre><\/div>\n\n\n\n<p>Compile, execute a API e atualize o browser. Veja que a documenta\u00e7\u00e3o j\u00e1 mudou.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" width=\"1024\" height=\"629\" src=\"https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-12-1024x629.png\" alt=\"\" class=\"wp-image-517\" srcset=\"https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-12-1024x629.png 1024w, https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-12-300x184.png 300w, https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-12-768x472.png 768w, https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-12.png 1092w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Agora temos a representa\u00e7\u00e3o do verbo GET. Ao clicar na seta do lado, veremos todas as informa\u00e7\u00f5es desse endpoint. Retorne no c\u00f3digo-fonte e altere conforme abaixo:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \" >unit API.Controller.Clientes;\n\ninterface\n\nuses\n  Horse,\n\n  System.StrUtils,\n  System.SysUtils,\n  System.Classes,\n\n  Horse.GBSwagger.Register,\n  Horse.GBSwagger.Controller,\n  GBSwagger.Path.Attributes,\n\n  API.Model.Clientes;\n\ntype\n  [SwagPath('v1', 'clientes')]\n  TControllerClientes = class(THorseGBSwagger)\n  private\n\n  public\n    [SwagGet('clientes', 'Descri\u00e7\u00e3o do Endpoint')]\n    [SwagResponse(200, TModelClientes, 'Retorno com sucesso')]\n    procedure DoListClientes;\n\n    [SwagPost('clientes', 'Descri\u00e7\u00e3o do Endpoint')]\n    [SwagResponse(200, TModelClientes, 'Retorno com sucesso')]\n    procedure DoPost;\n\n    [SwagPut('clientes', 'Descri\u00e7\u00e3o do Endpoint')]\n    [SwagResponse(200, TModelClientes, 'Retorno com sucesso')]\n    procedure DoPut;\n\n    [SwagDelete('clientes', 'Descri\u00e7\u00e3o do Endpoint')]\n    [SwagResponse(200, TModelClientes, 'Retorno com sucesso')]\n    procedure DoDelete;\n  end;\n\n\nimplementation\n\n{ TControllerClientes }\n\nprocedure TControllerClientes.DoDelete;\nbegin\n  FResponse.Send('Delete');\nend;\n\nprocedure TControllerClientes.DoListClientes;\nbegin\n  FResponse.Send('List');\nend;\n\nprocedure TControllerClientes.DoPost;\nbegin\n  FResponse.Send('Post');\nend;\n\nprocedure TControllerClientes.DoPut;\nbegin\n  FResponse.Send('Put');\nend;\n\ninitialization\n\nTHorseGBSwaggerRegister.RegisterPath(TControllerClientes);\n\nend.\n<\/pre><\/div>\n\n\n\n<p>Apenas adicionamos os novos endpoins com os verbos POST, PUT e DELETE. Agora sim, se quiser compilar e dar um refresh no browser, ver\u00e1 algo como:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"525\" src=\"https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-13-1024x525.png\" alt=\"\" class=\"wp-image-519\" srcset=\"https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-13-1024x525.png 1024w, https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-13-300x154.png 300w, https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-13-768x394.png 768w, https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-13.png 1045w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>O detalhe mais importante aqui. Quando voc\u00ea abrir as configura\u00e7\u00f5es do endpoint em qualquer verbo, ver\u00e1 o &#8220;Schema&#8221; de cada um. Qual JSON \u00e9 recebido e como podemos enviar os dados.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"606\" src=\"https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-14-1024x606.png\" alt=\"\" class=\"wp-image-520\" srcset=\"https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-14-1024x606.png 1024w, https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-14-300x178.png 300w, https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-14-768x454.png 768w, https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-14.png 1041w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Muito bom n\u00e3o \u00e9 mesmo? <\/p>\n\n\n\n<p class=\"has-large-font-size\"><strong>Melhorando a Documenta\u00e7\u00e3o<\/strong><\/p>\n\n\n\n<p>Show de bola, agora vamos imaginar algumas situa\u00e7\u00f5es. Digamos que o campo ID seja um autonum\u00e9rico no servidor, logo no verbo POST n\u00e3o precisamos inform\u00e1-lo, ou seja, podemos ocultar esse campo. Al\u00e9m disso, precisamos muitas vezes implementar par\u00e2metros no path, body ou query param. Como fazer isso?<\/p>\n\n\n\n<p>Bom, os par\u00e2metros s\u00e3o inclusos no Controller e os atributos de cada campo no Model, por isso separamos tudo pra ficar mais f\u00e1cil. Vamos fazer uma altera\u00e7\u00e3o simples para entendermos melhor.<\/p>\n\n\n\n<p>Digamos que precisamos informar qual o ID do registro que precisa ser Exclu\u00eddo no servidor, normalmente usamos um path param. Nossa url ficaria algo como:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \" >http:\/\/localhost:9000\/v1\/clientes\/123<\/pre><\/div>\n\n\n\n<p>Onde 123 \u00e9 o registro que ser\u00e1 exlu\u00eddo. Pra indicar a cria\u00e7\u00e3o de um par\u00e2metro na documenta\u00e7\u00e3o e tamb\u00e9m possibilitar fazer testes ao vivo no swagger, teremos que fazer uma anota\u00e7\u00e3o nova. Nesse caso no verbo Delete. Volte no c\u00f3digo e fa\u00e7a a seguinte altera\u00e7\u00e3o.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;SwagDelete('clientes', 'Descri\u00e7\u00e3o do Endpoint')]\n&#91;SwagResponse(200, TModelClientes, 'Retorno com sucesso')]\n&#91;SwagParamPath('id', 'ID do registro', True)]\nprocedure DoDelete;<\/code><\/pre>\n\n\n\n<p>Adicionamos o SwagParamPath indicando que ele \u00e9 um n\u00famero. Execute a API agora e veja documenta\u00e7\u00e3o. Abra o verbo get e note a inclus\u00e3o do par\u00e2metro.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"317\" src=\"https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-15-1024x317.png\" alt=\"\" class=\"wp-image-521\" srcset=\"https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-15-1024x317.png 1024w, https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-15-300x93.png 300w, https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-15-768x238.png 768w, https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-15.png 1045w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/go.hotmart.com\/A88975952B?dp=1&amp;utm_source=blog\" target=\"_blank\" rel=\"noreferrer noopener\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"150\" src=\"https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/Curso-Swagger.png\" alt=\"\" class=\"wp-image-527\" srcset=\"https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/Curso-Swagger.png 800w, https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/Curso-Swagger-300x56.png 300w, https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/Curso-Swagger-768x144.png 768w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/><\/a><\/figure>\n\n\n\n<p>Desse modo, quem estiver lendo nossa documenta\u00e7\u00e3o saber\u00e1 que podemos passar o ID do registro para ser deletado no lado servidor. Fa\u00e7a mais uma mudan\u00e7a. Vamos criar um novo recurso para o verbo Get, vamos permitir ter um query param, ou seja, filtros. Insira as anota\u00e7\u00f5es dessa forma:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;SwagGet('clientes', 'Descri\u00e7\u00e3o do Endpoint')]\n&#91;SwagResponse(200, TModelClientes, 'Retorno com sucesso')]\n&#91;SwagParamQuery('estado', 'Estado do cliente', False, False)]\n&#91;SwagParamQuery('cidade', 'Cidade do cliente', False, False)]\nprocedure DoListClientes;<\/code><\/pre>\n\n\n\n<p>Estamos criando dois par\u00e2metros do tipo Query Param n\u00e3o obrigat\u00f3rio, estado e cidade. Imagine que possamos talvez filtrar do lado servidor todos os clientes do estado de S\u00e3o Paulo e Cidade igual a Campinas. Claro que teremos que identificar os par\u00e2metros recebidos do lado servidor e fazer os respectivos selects, mas n\u00e3o vem ao caso agora. Com a cria\u00e7\u00e3o desses par\u00e2metros, agora temos a possibilidade de enviar a requisi\u00e7\u00e3o assim:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \" >http:\/\/localhost:9000\/v1\/clientes?estado=SP&amp;cidade=Campinas<\/pre><\/div>\n\n\n\n<p>E ao rodarmos a API os par\u00e2metros aparecer\u00e3o na documten\u00e7\u00e3o.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"661\" height=\"445\" src=\"https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-16.png\" alt=\"\" class=\"wp-image-522\" srcset=\"https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-16.png 661w, https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-16-300x202.png 300w\" sizes=\"(max-width: 661px) 100vw, 661px\" \/><\/figure>\n\n\n\n<p class=\"has-large-font-size\"><strong>Mudando os atributos do campo<\/strong><\/p>\n\n\n\n<p>Pra seguimos para o final do nosso artigo, vamos fazer algumas mudan\u00e7as no Model. N\u00f3s podemos determinar o tipo de dado do campo, valor m\u00ednimo, m\u00e1ximo, obrigat\u00f3rio, somente leitura, entre outros atributos. Para isso basta fazermos as devidas anota\u00e7\u00f5es nos campos no model. Acesse a unit do nosso TModelClientes e fa\u00e7a as modifica\u00e7\u00f5es como a seguir:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \" >uses\n  GBSwagger.Model.Attributes;\n\ntype\n  TModelClientes = class\n  private\n    FID : Integer;\n    FNome: string;\n    FDataDeInclusao : TDateTime;\n    FCreditoPreAprovado: Double;\n    FDiasPraPagar: Integer;\n  public\n    [SwagIgnore]\n    property ID : Integer read FID write FID;\n\n    [SwagString(100, 1)]\n    [SwagRequired]\n    property Nome: string read FNome write FNome;\n\n    [SwagDate('YYYY-DD-MM hh:mm:ss')]\n    property DataDeInclusao : TDateTime read FDataDeInclusao write FDataDeInclusao;\n\n    [SwagNumber(1000, 10000)]\n    property CreditoPreAprovado: Double read FCreditoPreAprovado write FCreditoPreAprovado;\n\n    [SwagNumber]\n    property DiasPraPagar: Integer read FDiasPraPagar write FDiasPraPagar;\n  end;<\/pre><\/div>\n\n\n\n<p>Pronto, as anota\u00e7\u00f5es foram feitas. Acho que d\u00e1 pra entender f\u00e1cil o que cada uma significa n\u00e9? Bem simples. Podemos determinar se \u00e9 uma string, n\u00famero, data. Qual valor m\u00ednimo e m\u00e1ximo, obrigat\u00f3rio, etc. Mas aten\u00e7\u00e3o, s\u00f3 \u00e9 poss\u00edvel fazer isso porque declaramos uma unit do Swagger l\u00e1 no uses, n\u00e3o esque\u00e7a. Rode a API agora e veja o resultado.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"613\" height=\"425\" src=\"https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-17.png\" alt=\"\" class=\"wp-image-524\" srcset=\"https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-17.png 613w, https:\/\/adrianosantostreina.com.br\/blog\/wp-content\/uploads\/2024\/04\/image-17-300x208.png 300w\" sizes=\"(max-width: 613px) 100vw, 613px\" \/><\/figure>\n\n\n\n<p>Note que h\u00e1 uma aba chamada Model e nela a configura\u00e7\u00e3o \u00e9 mostrada. Tudo que configuramos para cada campo foi mostrado, com isso o desenvolvedor que estiver lendo a documenta\u00e7\u00e3o saber\u00e1 exatamente como cada campo deve ser enviado ou recebido. Muito bom, n\u00e9?<\/p>\n\n\n\n<p class=\"has-large-font-size\"><strong>Torne-se um especialista em documenta\u00e7\u00e3o<\/strong><\/p>\n\n\n\n<p>Evidentemente que n\u00e3o \u00e9 poss\u00edvel mostrar tudo isso em \u00fanico artigo. Fiz o poss\u00edvel aqui para que voc\u00ea entendesse os primeiros passos na constru\u00e7\u00e3o de documenta\u00e7\u00f5es para suas APIs em Horse com Delphi e voc\u00ea deve estar com muitas d\u00favidas nesse momento, tais como:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Como fica minha documenta\u00e7\u00e3o quando a tabela for um Mestre\/Detalhe?<\/li>\n\n\n\n<li>E sobre HTTPS, como posso prosseguir?<\/li>\n\n\n\n<li>Como fa\u00e7o para documentar um campo do tipo imagem ou boleano?<\/li>\n<\/ul>\n\n\n\n<p>Enfim, h\u00e1 bastante coisa a ser aprendida. A boa not\u00edcia que te dou \u00e9 que temos um treinamento completo sobre o middleware GBSwagger que foi ministrado pelo pr\u00f3prio autor do middleware e explica tudo que voc\u00ea precisa saber. <\/p>\n\n\n\n<p>O valor tamb\u00e9m \u00e9 muito acess\u00edvel, s\u00e3o 4h de aulas, 100% pronta pelo valor de <strong>12x de R$ 14,87<\/strong> ou <strong>R$ 149,00 \u00e0 vista<\/strong>, voc\u00ea assiste ao conte\u00fado e constr\u00f3i uma documenta\u00e7\u00e3o profissional para suas APIs. Basta clicar no bot\u00e3o abaixo e garantir o seu curso com acesso <strong>IMEDIATO<\/strong>.<\/p>\n\n\n\n<div class=\"wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex\">\n<div class=\"wp-block-button\"><a class=\"wp-block-button__link wp-element-button\" href=\"https:\/\/go.hotmart.com\/A88975952B?dp=1&amp;utm_source=blog\" target=\"_blank\" rel=\"noreferrer noopener\">QUERO APRENDER TUDO SOBRE SWAGGER AGORA<\/a><\/div>\n<\/div>\n\n\n\n<p class=\"has-large-font-size\"><strong>Conclus\u00e3o<\/strong><\/p>\n\n\n\n<p>Em suma, a import\u00e2ncia de uma documenta\u00e7\u00e3o de API bem estruturada transcende o simples ato de disponibilizar informa\u00e7\u00f5es para desenvolvedores terceirizados. \u00c9 tamb\u00e9m crucial para os desenvolvedores internos, que se beneficiam enormemente de terem acessos claros e organizados \u00e0s funcionalidades e aos par\u00e2metros operacionais da API. Documentar uma API n\u00e3o s\u00f3 profissionaliza a entrega como eleva a relev\u00e2ncia e a utilidade da API, facilitando sobremaneira o entendimento e a integra\u00e7\u00e3o em diversos n\u00edveis de projetos de software.<\/p>\n\n\n\n<p>O uso do middleware GBSwagger, em espec\u00edfico, integra-se perfeitamente ao ambiente Delphi e ao framework Horse, proporcionando uma maneira eficaz e eficiente de acompanhar a evolu\u00e7\u00e3o da API sem a necessidade de publicar a documenta\u00e7\u00e3o em outros locais. Isso n\u00e3o s\u00f3 garante que a documenta\u00e7\u00e3o esteja sempre atualizada com a \u00faltima vers\u00e3o da API, mas tamb\u00e9m que ela esteja sempre acess\u00edvel e sincronizada com o desenvolvimento do projeto.<\/p>\n\n\n\n<p>Portanto, investir em uma documenta\u00e7\u00e3o de qualidade atrav\u00e9s do GBSwagger \u00e9 mais do que uma pr\u00e1tica recomendada; \u00e9 uma estrat\u00e9gia essencial para qualquer equipe de desenvolvimento que deseja garantir clareza, efici\u00eancia e um alto padr\u00e3o de profissionalismo em suas APIs.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Comunidade no <a href=\"https:\/\/t.me\/AdrianoSantosCommunity\">Telegram<\/a><\/p>\n\n\n\n<p>\ud83d\ude80Comente no campo abaixo \ud83d\udc47\ud83d\udc47\ud83d\udc47 o que achou e qual sua d\u00favida.<\/p>\n\n\n\n<p>Te vejo na pr\u00f3xima<\/p>\n\n\n\n<p>Adriano Santos<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>A documenta\u00e7\u00e3o \u00e9 um componente essencial no desenvolvimento de APIs, facilitando tanto para os desenvolvedores que criam a API quanto para aqueles que a consomem. Uma ferramenta amplamente reconhecida para essa finalidade \u00e9 o Swagger, que permite descrever a estrutura de suas APIs para que possam ser compreendidas e utilizadas por um p\u00fablico amplo. Neste [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":526,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[24,1,54],"tags":[20,14,21,12,55],"class_list":["post-502","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-api","category-blog","category-swagger","tag-api","tag-delphi","tag-horse","tag-rest","tag-swagger"],"_links":{"self":[{"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/posts\/502","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/comments?post=502"}],"version-history":[{"count":24,"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/posts\/502\/revisions"}],"predecessor-version":[{"id":538,"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/posts\/502\/revisions\/538"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/media\/526"}],"wp:attachment":[{"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/media?parent=502"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/categories?post=502"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/adrianosantostreina.com.br\/blog\/wp-json\/wp\/v2\/tags?post=502"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}