Git Product home page Git Product logo

horse's Introduction

Horse


Horse is an Express inspired web framework for Delphi and Lazarus.
Designed to ease things up for fast development in a minimalist way and with high performance.


⚙️ Installation

Installation is done using the boss install command:

boss install horse

⚡️ Quickstart Delphi

uses Horse;

begin
  THorse.Get('/ping',
    procedure(Req: THorseRequest; Res: THorseResponse)
    begin
      Res.Send('pong');
    end);

  THorse.Listen(9000);
end.

⚡️ Quickstart Lazarus

{$MODE DELPHI}{$H+}

uses Horse;

procedure GetPing(Req: THorseRequest; Res: THorseResponse);
begin
  Res.Send('Pong');
end;

begin
  THorse.Get('/ping', GetPing);
  THorse.Listen(9000);
end. 

🧬 Official Middlewares

For a more maintainable middleware ecosystem, we've put official middlewares into separate repositories:

Middleware Delphi Lazarus
horse/json    ✔️     ✔️
horse/basic-auth    ✔️     ✔️
horse/cors    ✔️     ✔️
horse/stream    ✔️     ✔️
horse/jwt    ✔️     ✔️
horse/exception    ✔️     ✔️
horse/logger    ✔️     ✔️
horse/compression    ✔️     ✔️

🌱 Third Party Middlewares

This is a list of middlewares that are created by the Horse community, please create a PR if you want to see yours!

Middleware Delphi Lazarus
bittencourtthulio/etag    ✔️     ✔️
bittencourtthulio/paginate    ✔️     ✔️
bittencourtthulio/cachecontrol    ✔️     ❌
gabrielbaltazar/gbswagger    ✔️     ❌
willhubner/socketIO    ✔️     ❌
dliocode/ratelimit    ✔️     ❌
dliocode/slowdown    ✔️     ❌
giorgiobazzo/upload    ✔️     ❌
dliocode/query    ✔️     ❌
CarlosHe/healthcheck    ✔️     ❌
CarlosHe/staticfiles    ✔️     ❌
CachopaWeb/horse-server-static    ✔️     ✔️
arvanus/horse-exception-logger    ✔️     ✔️
claudneysessa/Horse-CSResponsePagination    ✔️     ❌
claudneysessa/Horse-XSuperObjects    ✔️     ❌
andre-djsystem/horse-bearer-auth    ✔️     ✔️
andre-djsystem/horse-manipulate-request    ✔️     ✔️
andre-djsystem/horse-manipulate-response    ✔️     ✔️
antoniojmsjr/Horse-IPGeoLocation    ✔️     ❌
antoniojmsjr/Horse-XMLDoc    ✔️     ❌
isaquepinheiro/horse-jsonbr    ✔️     ❌
IagooCesaar/Horse-JsonInterceptor    ✔️     ❌
dliocode/horse-datalogger    ✔️     ❌
marcobreveglieri/horse-prometheus-metrics    ✔️     ❌

Delphi Versions

Horse works with Delphi 11 Alexandria, Delphi 10.4 Sydney, Delphi 10.3 Rio, Delphi 10.2 Tokyo, Delphi 10.1 Berlin, Delphi 10 Seattle, Delphi XE8 and Delphi XE7.

💻 Code Contributors

⚠️ License

Horse is free and open-source software licensed under the MIT License.

📐 Tests

tests Console Coverage VCL Coverage

horse's People

Contributors

andre-djsystem avatar antoniojmsjr avatar arvanus avatar bragaped avatar cachopaweb avatar carloshe avatar claudneysessa avatar dliocode avatar dshumko avatar fravemelautrial avatar gabrielbaltazar avatar glerystonmatos avatar hunsche avatar iagoocesaar avatar igorbastosib avatar isaquepinheiro avatar julio-ferrari avatar juliosenha avatar marcobreveglieri avatar marcosfincotto avatar mateusvicente100 avatar mfernstrom avatar michaliskambi avatar natanaelribf avatar ramyres110 avatar slipkbode avatar snakeice avatar tbisistemas avatar viniciussanchez avatar willhubner avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

horse's Issues

Running on windows fails to load ssleay32.dll

I did not find any guide to make horse work in windows, the one I saw called "Horse: A revolução no REST" talks about compiling for linux. I think OpenSSL libraries are available in linux but i don't know how to get them correctly in windows.

Erro ao Compilar Projeto Horse

Estou realizando a instalação do framework, inclui no source path do delphi, porem ao compilar o projeto ocorre o seguinte erro:

[dcc32 Error] E2223 $DENYPACKAGEUNIT 'Web.WebBroker' cannot be put into a package,

Uso o Delphi 10.3

Podem me ajudar?

SSL

Como utilizar Horse com SSL?

Deregister Endpoint

Hi,

Greate library!
However, I was wondering how do I deregister an endpoint during runtime?

MaxConnections fixo em 32

Verifiquei o problema no Delphi Rio 10.3, após a quantidade de conexões chegar a 32 o retorno passa a ser [Maximum number of concurrent connections exceeded. Please try again later], independente da definição da propriedade MaxConnections do Horse.

Foi resolvido inserindo o seguinte código na linha 82 de Horse.pas:
if FMaxConnections > 0 then
WebRequestHandler.MaxConnections := FMaxConnections;

Implementei compatibilidade para modulo Apache.

Implementei a compatibilidade do Horse com o Apache 2.4. Por enquanto só testei no windows, depois vou ver como fica no linux, mas funcionou legal.
Só tem que tomar cuidado com o middleware de log, lembrando que a pasta de execução do apache é a pasta bin, para salvar o log do logger tem que usar ../logs. Se ele não encontrar um caminho válido da violação de memória no Apache.

Segue o código que implementei e um exemplo. Se acharem minha contribuição interessante e puderem adicionar ao projeto.

Claudio
Horse.Apache.zip
Sample.zip

ToString in TObject if not parsed

When running the entire middleware chain and the return goes blank, provide ToString to Content TObject to help identify the return in the accidental absence of midleware uses.

ISAPI Error

I'm trying to use ISAPI module on IIS10 (windows 10 or Windows Server 2019)
With a simple demo supplied this error is showed.

Internal Application Error Unbalanced stack or queue operation

Creating a dll isapi using REST Server Datasnap wizard works ok.

Prefix middleware

Currently, if you need to define "api" on all URLs, it has to be done on all endpoints.

  App.Get('/api/customers',
    procedure(Req: THorseRequest; Res: THorseResponse; Next: TProc)
    begin

    end);

  App.Get('/api/products',
    procedure(Req: THorseRequest; Res: THorseResponse; Next: TProc)
    begin

    end);

Create middleware for this.

begin
  App := THorse.Create(9000);

  App.Use(Prefix('api'));

  App.Get('/customers',
    procedure(Req: THorseRequest; Res: THorseResponse; Next: TProc)
    begin

    end);

  App.Get('/products',
    procedure(Req: THorseRequest; Res: THorseResponse; Next: TProc)
    begin

    end);

  App.Start;
end.

Stop Service

Boa tarde,

É possível startar o horse sem bloquear o fluxo da aplicação? pensei em talvez colocar em uma thread a parte, mas não vi opção de fazer um stop.

O leque de possibilidades que o horse abre é muito grande, um cenario que tenho aqui é para anexar comprovantes de pagamento em titulos financeiros, no sistema desktop.
Este anexo pode ser um arquivo pdf ou uma foto. No caso da foto, pensei em fazer um app no celular para tirar a foto e enviar para o sistema.
Seria simples fazer um serviço e deixar rodando no servidor para isso, mas como são muitas empresas utilizando, inviabiliza a instalação de um serviço em casa empresa, pensei em startar a instancia do horse em um formulario exibindo um qrcode com a url do servico, para que o aplicativo faça a foto e envie ao sistema. Após concluir esse processo poderia dar um stop no horse.

Seria possível trabalhar desta forma?

Grato

Incompabilitade entre os middlewares Compression e Paginate

Ao usar o middleware Paginate juntamente com o Compression acontecem problemas.

Conforme a ordem do registro o problema muda.

Se usar nessa ordem não acontece erro mas a paginação não funciona.
App.Use(Compression());
App.Use(Paginate);

Se inverter a ordem o send não é enviado e gera um erro no client.
App.Use(Paginate);
App.Use(Compression());

MemoryLeaks - Octet-Stream

Método para Post*

THorse.Post('/backup',
procedure(Req: THorseRequest; Res: THorseResponse; Next: TProc)
var
Stream: TmemoryStream;
begin
Stream := Req.Body;
if Stream <> nil then
Stream.SaveToFile(Dir);
end);

Recebo o arquivo Stream do módulo Client salvo em disco sem problemas, mas quando
se trata de a API receber arquivos maiores e a transferência é paralela com duas ou mais, caso seja dois, um dois arquivos não é liberado de memória, ou seja, apenas o ultimo é liberado de memória, é como o Horse criasse apenas a instancia da requisição
e utilizasse uma variável stream para todas as requisições.
Chega uma requisição Stream = Stream_Client1, próxima requisição paralela Stream = Stream_Client2, com isso mesma variável recebeu dois valores sendo assim o endereço de memória(ponteiro) do primeiro stream foi perdido ficando em memória. Com isso o consumo de memoria aumenta, causando Out of Memory e no lado do Client Conexão abortada entre outros erros, segue print da Memoryleak dos arquivos perdidos em memoria. Primeiro erro, módulo Client, erro inferior Módulo Servidor ao finalizar a aplicação. Sendo assim essa foi minha analise quanto o que ocorre com varias transferências.
ATENÇÂO: o mesmo só ocorre em transferências simultânea, a mesma executada em sequencia após a outra não ocorre.

Informação do Servidor:
Dell R620 + 128GB de Ram
Sistema Operacional Windows Server 2019 Essentials
Sendo que a API roda em uma VM com 16GB de Ram e 4 Core.
image

Setar provider a ser usado.

Implementar opção de setar o Provider a ser usado pelo Horse, com esta opção seria possível criar novos provider's sem a necessidade de alterar o core do Horse.

Conflito entre o uso de aplicações ISAPI

Olá Time Horse,

Parabéns pelo framework!!!

Comecei a testar o framework essa semana e encontrei um problema com a forma que separaram o instanciamento de aplicação ISAPI vs StandAlone e isso conflita em várias parte, abaixo vou citar os exemplos para que possam avaliar se concordam comigo, lembrando que minhas sugestões são para o melhora e não uma crítica:

Middleware: por default reparei que sempre usam a classe horse e se eu iniciar minha aplicação usando o horse.isapi já irá causar conflito.

Outra situação, todos os meus testes serão em modo standalone para poder debugar a aplicação, imagina que em acada classe onde registro os meus caminhos de consumo no servidor recebendo o Thorse como parâmetro, terei que usar no uses horse, agora se precisar compilar um ISAPI, terei que mudar todas as classes para horse.isapi para poder compilar, isso não se tornou funcional, sem contar toda a dificuldade para criar um middleware compatível, para contornar isso estou trabalhando com o horse.core de vez do horse, mas como continuo explicando isso acaba sendo paliativo, pois não resolve outros problemas.

Outro problema é ter propriedades publicas no horse e não existir no horse.isapi, isso quebra o principio de padrões de desenvolvimento onde deveria trocar para outra classe filha e não quebraria o código, cito o middleware do swagger que usa a leitura da propriedade porta e horse no use, agora se muda para horse.isapi na instancia do meu projeto, o middleware para de funcionar, podem pensar que isso seja um problema no middleware, sinceramente não acho que seja uma questão a ser ajustada no middleware e sim no nucleo do horse.

Minha sugestão seria que todas variáveis publicas sejam no horse.core (se ainda for existir essa separação de horse.isapi, provavelmente vão ter que criar horse.service para gerar serviços para windows onde muda algumas coisas também), mesmo que no isapi não seja utilizado essas propriedade, isso já evitar alguns problemas.

Um outra coisa seria não existir duas classes com o objeto Thorse e sim existir somente uma e essa questão de ser isapi, console, service, etc seja passado como parametro no create do Thorse.Create( THorseIsapi.Create ) e usar o start do objeto passado no parametro.

Sei que existem diversas formas de resolver os pontos que citei, essa foi só uma ideia que tive, os exemplos existentes no momento são usando somente o arquivo do projeto, mas em um projeto com as classes todas separadas que precisam registrar no servidor vai ficar mais evidente o problema que comentei, espero ter explicado de uma forma que possam entender.

Desejo sucesso ao projeto!!!

Memory Leak

Boa noite.

Constatei o vazamento em duas situações.

1a. Quando a requisição espera um parâmetro e ele não é enviado.
2a. Quando a requisição vem do axios(JS) mesmo com todos os parâmetros o vazamento também acontece.

Observação: Os parâmetros estão sendo enviados via query é pelo método GET.

websocket support?

Hi, I don't use horse yet, but I had built-ed a websocket client for Delphi (and probably pascal too)
Does horse has websocket support?
If not, is there interest to add Websocket do Horse?
Thanks

Erro StatusCode

Ao tentando retornar um StatusCode diferente não está alterando, sempre retorna 200.
Tentei assim:

Res.Status(THTTPStatus.Unauthorized).Send('Credenciais inválidas.');

Ao mudar a ordem funcionou assim:
Res.Send('Credenciais inválidas.').Status(THTTPStatus.Unauthorized);

Usando FDQuery ou ClientDataSet, mas em vão.

Me tirem uma dúvida, tenho um servidor DataSnap já rodando e funcionando... semana passada procurando algo mais robusto e fácil achei o Horse, mas pesquisei em tudo quanto foi local, mas não consigo achar nada usando Horse com SQL Server e nos testes que faço não dá certo...
Tentei algo como abaixo:

Tenho um DataModule com a conexão do banco (TFConnecttion) e as Querys (TFDQuery)
O Token está sendo gerado certinho, porém rrtornar ums Select simples não vai.
...
App.Get('/lista',JwtAuth,
procedure(Req: THorseRequest; Res: THorseResponse; Next: TProc)
begin
dmInt.qryCliente.Close;
dmInt.qryCliente.SQL.Text := 'Select top(5) cod_cliente, nome, cpf, dtnasc, sexo, celular, fone1,'#13+
' fone2, email, endereco, numero, complemento, cep, cidade, '#13+
' uf, bairro, psenha, dtcadastro, cod_logradouro, cod_bairro '#13+
' From JsonCliente ';
' Where Cod_Cliente = :CodCliente'+#13;
' Order By cod_cliente desc ';
dmInt.qryCliente.Open;
Result := dmInt.qryCliente.AsJSONArray;
dmInt.qryCliente.Close;

  Res.Send(LBody);

vocês poderiam ao menos me dá um norte?

Memory Leak

O middleware Paginate está com memoryleak.

Para simular o vazamento basta rodar o exemplo dele e fazer a requisição.

I/O error 105

Hi guys,
I'm trying to run a Horse app as a windows services, but a get "I/O error 105".
Have you tested this before?
Regards

Vazamento de memória

Detectei no Horse alguns vazamentos de memória.

Coloquei o comando "ReportMemoryLeaksOnShutDown" no projeto, abri o prompt de comando e executei o servidor por lá. ao finaliza-lo, o prompt irá informar os vazamentos.

Isso ocorre tanto com ou sem adição de middlewares.

image

InitializeContentFields retornando erro "Duplicates not allowed"

Ola, bom dia.

Após a inclusão desta função comecei a ter como resposta "Duplicates not allowed".

Ocorre quando utiliza o Body de um post e informa um Json Array - exemplo [{"controle":1}, {"controle":2}]

Quando envia um Objeto Json {} o problema não ocorre.

Será que perdi alguma outra Implementação e deixei de configurar algo de forma correta ? ou é um caso a ser corrigido mesmo ?

Por enquanto para poder utilizar desta forma estou comentando o trecho, como mostrado abaixo :

constructor THorseRequest.Create(AWebRequest: {$IF DEFINED(FPC)}TRequest{$ELSE}TWebRequest{$ENDIF});
begin
FWebRequest := AWebRequest;
InitializeQuery;
InitializeParams;
//// InitializeContentFields;
InitializeCookie;
end;

Define people to review commits

The idea is to create a team to screen and review the "pull requests" and "issues" of the community.

This team needs to understand and check the topics already created for version 2.0.0!

Problema com Body<T> e algumas sugestões.

Boa tarde,

Desculpe incomodar, mas estou fazendo varios testes com o horse e estou achando muito top.

Tive um probleminha com a função Body usando generics, neste caso não retornou meu objeto corretamente.. tive que fazer desta forma,

login := TJson.JsonToObject(req.Body);

pode ser que eu esteja interpretando errado a rotina Body.

Outra coisa que notei, quando quero enviar um status code se nao enviar um corpo no resultado, o postman recebe um exception e nao o status code retornado... por exemplo:

// assim da erro
resp.Status(THTTPStatus.BadRequest.ToInteger);

// assim funciona
resp.Send('não enviado dados para login').Status(THTTPStatus.BadRequest.ToInteger);

Notei também que é necessário gerar um EHorseCallbackInterrupted para que o processamento não continue, aqui seria apenas uma sugestão...

// trecho de codigo atual
if login = nil then
begin
resp.Send('não enviado dados para login').Status(THTTPStatus.BadRequest.ToInteger);
raise EHorseCallbackInterrupted.Create;
end
else if (login.login <> 'marciano') or (login.senha <> '123') then
begin
resp.Send('Unauthorized').Status(THTTPStatus.Unauthorized.ToInteger);
raise EHorseCallbackInterrupted.Create;
end;

// trecho otimizado (necessario implementacoes no horse)
if login = nil then
// resp.raiseBadRequest('com mensagem');
resp.raiseBadRequest(); // sem mensagem
else if (login.login <> 'marciano') or (login.senha <> '123') then
resp.raiseUnauthorized();

Desculpe se ja tem coisas que já estão na nova versão.
Também fico a disposição para implementar as sugestões.

A misspelling in your readme.md

Sorry to disturb, but I've noticed a misspelling (an) in your readme.md in the following line:

For an more maintainable

The correct (a) is:

For a more maintainable

By the way, if you want any help with the documentation or something (code), I'd be happy.

Write / Write - Application VCL Form

I did not understand the use of the Write and Read line in Horse.pas.
Because when used in conjunction with the Service or VCL, an error occurs.
For these screen exits, wouldn't it be better to pass a function to Log Horse?
If something needs to be displayed, the passed function is responsible for the display / translation, which would generate console and VCL compatibility.

[ 2 DÚVIDAS] - Horse

Boa tarde, preciso criar uma api, e meu cliente quer que seja em Horse usando JWT, porém em 2 endpoints não vai ter autenticação, que é o que vai retornar o JWT, GET /gettoken/ e um POST /createuser/ , como seria esses 2 endpoints? o resto vai ter autenticação JWT, procurei antes de postar aqui e não achei nada relacionado

Duvida 2, seria um console Application mesmo, pelo que mapeamos, vai ter uns 60 endpoints, ele ficaria um embaixo do outro mesmo ou tem como separar melhor? sei la colocar um método que retorna so endpoints de pagamentos: ListEndpointsPagto() e outro de usuário: ListEndpointsUsers() ficando + ou - assim:

function ListEndpointsUsers()
var
  retornarEndpoints: nao sei o tipo;
begin
   retornarEndpoints :=  retornarEndpoints + THorse.Get('/ping',
    procedure(Req: THorseRequest; Res: THorseResponse; Next: TProc)
    begin
      Res.Send('pong');
    end);
    
     retornarEndpoints :=  retornarEndpoints + THorse.Post('/test',
    procedure(Req: THorseRequest; Res: THorseResponse; Next: TProc)
    begin
      Res.Send('pong');
    end);
    result :=  retornarEndpoints;
end;
ListEndpointsUsers();
.....

hj na documentação é um "GET" embaixo do outro né?

THorse.Get('/ping',
    procedure(Req: THorseRequest; Res: THorseResponse; Next: TProc)
    begin
      Res.Send('pong');
    end);
THorse.Post('/test',
    procedure(Req: THorseRequest; Res: THorseResponse; Next: TProc)
    begin
      Res.Send('pong');
    end);
.....

Router Regex (URL-Parameters)

Hi,

Is it possible to define a route using regular expressions?
Is it possible to define an endpoint containing URL-parameters?

For instance:
When I have registered the following endpoint: Localhost:9000/api/locate/
and I send a request to Localhost:9000/api/locate/?name=Apple
"not found" is returned.

See ExpressJs for inspiration:
https://expressjs.com/en/guide/routing.html

Bootstrap Sample

hello Vinicius,

is possible to you, add a small sample in bootstrap to create a datatable or table from dataset in horse?
also put values on variables in html page, imagine i have a total sales variable, in server, i calculate the value and change the variable value on the html?

would be very grateful for the help.

Listen on Multiple Ports

Hi,

Is it possible to listen on multiple ports using Horse?

Maybe it can be achieved by just creating multiple Horse Instances?

Https/ssl

O Horse está funcionando com HTTPs?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.