PoC — Construindo um Web Server Simples no Delphi

Samuel R. O.
5 min readDec 23, 2022

--

O projeto Horse, resumo.

Antes de falar do exemplo deste post, nada mais óbvio do que falar primeiramente da biblioteca Horse. Atualmente, ela é a maneira mais prática para criar um servidor web em Delphi. Temos a biblioteca ICS também, mas em termos de simplicidade, o Horse ganha. Foi arquitetado para ser similar ao NodeJS. Quem já fez uma API em NodeJS e depois tentou fazer uma API em Horse quase não percebe diferença entre elas. A lógica é idêntica.

https://github.com/HashLoad/horse

Um exemplo prático

Entretanto, hoje meu objetivo nesse post é mostrar um exemplo ainda mais simples. Pense em uma estrutura molecular. O Horse é super completo e pode ser comparado à uma estrutura molecular já bem formada. Mas hoje vamos dar um zoom nessa estrutura molecular e começar a analizar os átomos que fazem as ligações. Vamos conseguir até ver os elétrons passando de um átomo para outro e todas as coisas que nem Niels Bohr teve o privilégio de ver. Essa é a analogia que eu quero deixar. Hoje veremos qual a forma mais simples de se criar um servidor web com componentes nativos no Delphi.

IdHTTPServer, IdContext, IdCustomHTTPServer.

Aos programadores Delphi, esses nomes te soam familiar? Pois é, eu já falei muito mal da biblioteca Indy e até amaldiçoei ela quando eu comecei a programar em Delphi mas hoje eu me arrependo do que eu fiz. Essa biblioteca, apesar de não ser muito flexível, é muito completa também. Dá para fazer MUITA, mas MUITA coisa com ela. Esses dias atrás me deparei com um problema que envolvia server side events e quem me salvou foi o Indy. Inclusive, o projeto Horse também usa o Indy por baixo dos panos na sua implementação. É com essa biblioteca que vamos montar nosso exemplo hoje.

Console App

Primeiro, vamos criar uma aplicação console para exemplificar de maneira mais simples. Na IDE do Delphi em "File > New > Console Application — Delphi". Salve tudo e coloque um "ReadLn" para não fechar a aplicação. No final vamos ter isso:

Classe “Server”

Depois disso, vamos criar mais uma unit no projeto e chamá-la de “Server”. Esta unit vai conter uma classe para criar a instância do nosso servidor. Crie ela, adicione um “constructor” e uma “class function” para conseguirmos chamar a construção dela mais a frente no projeto. No final vamos ter um código semelhante a este:

Repare apenas que a “class function” tem que retornar a própria classe "TServer".

Units do Indy

Agora vem a parte de usar a biblioteca Indy para conseguir criar o servidor web. Adicione as três unit do subtítulo desta seção, a saber, as units “IdHTTPServer”, “IdContext”, “IdCustomHTTPServer” na seção “uses” da unit “Server” — e também adicione um field privado na classe do tipo “TIdHTTPServer”. Para simplificar, chamaremos este field de “FServer” e criaremos ele juntamente no momento da criação da nossa classe TServer. Veja como a unit ficará:

Escolhi por padrão a porta 7070 porém mais tarde faremos uma pequena implementação para mudar isso. Agora vem a parte legal. No momento que o servidor receber uma requisição, alguns eventos da classe TIdHTTPServer são disparados. O evento de nosso interesse é aquele chamado de “OnCommandGet”. Iremos criar uma função chamada “CallBack” na nossa classe “TServer” que vai ser referenciada neste evento “OnCommandGet”. Esta função precisa de três coisas:

  1. Um objeto representando o contexto do servidor, ou em outras palavras, o estado dele (ex.: sessões, cookies etc…).
  2. Um objeto representando a requisição — Request.
  3. Um objeto representando a resposta — Response.

Essa função receberá estes três parâmetros e na implementação dela vamos criar um JSON de resposta com um código de status para o usuário. Ela ficará desta forma:

Eu decidi ocultar os outros métodos para simplificar a visualização, mas vou mostrar a classe completa no final do artigo.

Agora para finalizar o exemplo, vamos criar um método chamado “Listen” que recebe um parâmetro representando o número da porta. Nesse método vamos fazer 4 coisas importantes:

  1. Configurar a porta do field “FServer”
  2. Atribuir o método “CallBack” ao método “OnCommandGet” do field “FServer”
  3. Ativar a conexão
  4. Mostrar uma mensagem para o usuário dizendo que o servidor está ativo.

A nossa classe deve ficar assim — os outros métodos foram ocultos para simplificar a visualização:

Isso! Agora é só usar! Para isso, volte ao arquivo principal do projeto e instancie nossa classe “Server” com o método "New". Nela podemos passar o número da porta que desejamos:

Adicionamos apenas um “ReadLn” para não fechar nossa aplicação. Pronto! Agora compile, builde e execute o projeto. Vai aparecer a mensagem pedindo para você liberar a porta no FireWall e depois disso o programa passará a escutar as requisições vindo dessa porta:

Alerta do Firewall

Agora se fizermos uma requisição do tipo GET para o endereço local de nossa máquina na porta que escolhemos (http://localhost:9090) o json de resposta com o status code 200 vai aparecer com sucesso! Abra o Insomnia ou Postman e faça isso. Veja:

Resposta da requisição no Insomnia

E agora, nosso velho jargão “isso é muito difícil de fazer no Delphi” já não existe mais.

É claro que este é um servidor muito simples ainda, como disse, isso é como se fosse o átomo de uma molécula. Claro que precisa ser feito várias coisas ainda como diferenciar o verbo da requisição, ter suporte para conexões seguras via SSL, e várias outras coisas. O objetivo desse post não foi dizer sobre isso. Para isso temos outras bibliotecas que nos ajudam conforme eu mencionei no início deste post. Mas essa foi uma demonstração simples de uma PoC (Prova de Conceitos) sobre como criar um servidor web no Delphi.

Quanto ao mais, nos falamos no próximo post!

Classe completa

--

--