[DAPUG] Nemmeste måde at opbygge et REST API i Delphi.

28 views
Skip to first unread message

Thomas Lassen

unread,
Jun 16, 2025, 6:34:32 AMJun 16
to DAPUG
Hej Liste.

Vi har fået den ide at det kunne være smart at udstille noget af vores beregningsfunktionalitet via et REST-api.

Vi har noget gammel kode liggende, lad os sige det ligger i grundlag.pas, som vi gerne vil kalde. via nogle http-requests.

Vi skal kunne lave kald med dynamisk angivne parametre fx

http://<url>:8000/BEREGNSPEC/<SPECIFIKATION>.

Ovenstående skal så resulterer i at en funktion bliver kaldt i grundlag.pas, som kan parse strengen, og foretage nogle beregninger på baggrund af indholdet.

Feltet er meget nyt for mig, så jeg vil høre om der nogle der kan bidrage med gode inputs til hvordan vi på en let måde kan komme i gang, men også med noget vi regner kan bruges mange år frem.

På forhånd tak.

Med venlig hilsen
Thomas Lassen

Jens Fudge

unread,
Jun 16, 2025, 6:51:26 AMJun 16
to da...@googlegroups.com, DAPUG
Jeg er blevet utroligt glad for et kommercielt produkt der hedder XData. Det er fra TMS Software.

Helt basalt har du en service på serversiden som du har lavet med et interface.
Interfacet "user" du også i klienten.

På serversiden lægger du interfacet i en fil og dekorerer det med attributter afhængig hvad der skal være på det:

[Authorize]
function GetBeregning(x, y : integer): TberegnetObject;

Thats it.


Du kan naturligvis godt returnere integer eller floats. Dette var blot for at angive at du kan returnere objecter.

På klienten:

var lService := TMyService;

myObject :=   lService.GetBeregning(4, 6);


(Ovenstående er pseudokode, og der er lidt syntax der skal på plads.)

Alt det med at parse ligger pakket ind i XData

Dr Holger Flick har lavet en del video'er med hvordan man gør. Det er Wagner Landgraf der har lavet frameworket, og det spiller ganske enkelt MAX.


Bemærk: Det kræver at du arbejder med Delphi på både Serverside og klientside




--
Du har modtaget denne besked, fordi du abonnerer på gruppen "DAPUG" i Google Grupper.
Hvis du vil ophæve abonnementet på denne gruppe og ikke længere modtage mails fra den, skal du sende en mail til dapug+un...@googlegroups.com.

Thomas Riedel, LogiHouse

unread,
Jun 16, 2025, 7:04:58 AMJun 16
to da...@googlegroups.com

Du kan bruge IndyHTTPServer, feks:

procedure TForm1.IdHTTPServerCommandGet(...);
begin
  if ARequestInfo.Document .StartsWith('/api/beregn' then
  begin
      AResponseInfo.ContentText :=   Grundlag.Beregn(...);
   end;
   AResponseInfo.ContentType := 'application/json';
end;

Her skal Grundlag.Beregn returnere svaret som string / JSON, eg: '{result:1234}'

Den kan også fungere direkte som HTTPS-server,  men den nemmeste måde at lave en HTTPS-server er at installere NGINX ovenpå Indy- HTTP-serveren
NGINX sørger så for kryptering, - det kræver et domain og et certifikat.

mvh Thomas 



--
Du har modtaget denne besked, fordi du abonnerer på gruppen "DAPUG" i Google Grupper.
Hvis du vil ophæve abonnementet på denne gruppe og ikke længere modtage mails fra den, skal du sende en mail til dapug+un...@googlegroups.com.
Du kan se denne diskussion ved at gå til https://groups.google.com/d/msgid/dapug/CABUWFUKEKqGuPXkJsgQP4ukcNfKTaZOadaToUfMBNGGn4xom0A%40mail.gmail.com.


--
LogiHouse A/S
tlf +45 2840 1070
Thomas Riedel
Storkebakken 10
2400 København NV

GlennKonnekt | Glenn Dufke

unread,
Jun 16, 2025, 7:50:21 AMJun 16
to da...@googlegroups.com
Hej Thomas,

Som Jens er inde på så er TMS XData et rigtig godt bud, specielt hvis du parer det med TMS Data Modeler og Aurelius ORM, de kan automatisk håndtere generering af ORM mapping mv.

Hvis du er begrænset af budget, så kan jeg også anbefale det open source middleware framework Delphi MVC Framework fra Daniele Teti som har alle de gængse moduler hvis du bla skal generere Swagger openapi doc, lave en web frontend med htmx eller håndtere JWT tokens.

Jeg vil ikke anbefale at håndrulle det med indy http serveren som andre er inde på da der er større krav til bla sikkerhed nu om dage.

Skal du håndtere https, vil jeg anbefale at bruge en reverse proxy. Afhængig af omfanget og setup kan det være med fx Caddy web serveren, Cloudflare Tunnels eller HAProxy.

--------------------------------------------------------------------
Med venlig hilsen / Kind regards

Glenn Dufke
Embarcadero MVP - Building the next gen apps with Delphi
g...@gkon.dk
LinkedIn: www.linkedin.com/in/glenn-dufke-b3538a39

Confidentiality notice
This e-mail, including any attachment, may contain confidential and privileged information.
If you have received it by mistake, please notify us by e-mail and delete this e-mail and any attachment from your computer system immediately.
Thank you!

Fortrolighedserklæring
Denne e-mail og vedhæftede bilag kan indeholde fortrolige og beskyttede oplysninger.
Hvis De ved en fejl har modtaget denne e-mail, anmodes De venligst straks om at give afsenderen besked via e-mail og slette denne e-mail og bilag fra Deres system omgående.
Mange tak!


------ Original Message ------
From "Thomas Lassen" <lassen...@gmail.com>
Date 16/06/2025 12.34.14
Subject [DAPUG] Nemmeste måde at opbygge et REST API i Delphi.

--

Sean Dollard

unread,
Jun 16, 2025, 10:31:15 AMJun 16
to da...@googlegroups.com

Hej Thomas,

 

Vedhæftet simpel rest server, basis http (for https se Thomas Riedel’s henvisning til NGINX).

 

Den klarer det grundlæggende for dig. Brug den eller tag hvad du kan bruge som inspiration 😊

 

Uses

  IdCustomHTTPServer,

  IdGlobal,

  IdContext,

  Trendware.Rest.Server,

  System.JSON,

  Trendware.Rest.ServerUtils;

 

  T…

  public

    RestServer: Trendware.Rest.Server.TRestServer;

    procedure ManageGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo; elementCount: Integer);

    procedure ManagePost(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo; elementCount: Integer);

    procedure ManageDelete(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo; elementCount: Integer);

    procedure ManagePut(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo; elementCount: Integer);

  end

 

    RestServer := TRestServer.Create(nil);

    try

      RestServer.Username := ';

      RestServer.Password := ';

 

      RestServer.OnManageDelete := ManageDelete;

      RestServer.OnManageGet := ManageGet;

      RestServer.OnManagePost := ManagePost;

      RestServer.OnManagePut := ManagePut;

 

      RestServer.Port := 12345;

      RestServer.Active := True;

    except

      RestServer.Active := False;

      RestServer.Free;

      raise;

    end;

 

procedure T….ManageDelete(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo; elementCount: Integer);

 

  procedure responseOK;

  begin

    AResponseInfo.ResponseNo := 200;

    AResponseInfo.ContentType := 'application/json';

    AResponseInfo.CharSet := 'utf-8';

    AResponseInfo.ContentText := '{"status": "ok"}';

    AResponseInfo.ContentLength := Length(UTF8String(AResponseInfo.ContentText));

  end;

 

  procedure responseFailed;

  begin

    AResponseInfo.ResponseNo := 200;

    AResponseInfo.ContentType := 'application/json';

    AResponseInfo.CharSet := 'utf-8';

    AResponseInfo.ContentText := '{"status": "not found"}';

    AResponseInfo.ContentLength := Length(UTF8String(AResponseInfo.ContentText));

  end;

 

  procedure responseFailedException(e:Exception);

  begin

    AResponseInfo.ResponseNo := 200;

    AResponseInfo.ContentType := 'application/json';

    AResponseInfo.CharSet := 'utf-8';

    AResponseInfo.ContentText :=

     '{"status": "exception",' +

      '"exception": "'+e.Message+'"}';

    AResponseInfo.ContentLength := Length(UTF8String(AResponseInfo.ContentText));

  end;

 

var

  path, fext: string;

begin

 

  if (elementCount = 1) and (AnsiCompareText(TRestServer.GetElement(ARequestInfo.Document, 1), 'deleteFile') = 0) and (ARequestInfo.Params.Count > 0) then

  begin

    path := ARequestInfo.Params[0];

 

    CoInitialize(nil);

    try

      fext := ExtractFileExt(path);

      if (AnsiCompareText(fext, '.mp4') <> 0) and

         (AnsiCompareText(fext, '.avi') <> 0) and

         (AnsiCompareText(fext, '.mov') <> 0) and

         (AnsiCompareText(fext, '.m4v') <> 0) and

         (AnsiCompareText(fext, '.asf') <> 0) and

         (AnsiCompareText(fext, '.wmv') <> 0) and

         (AnsiCompareText(fext, '.3g2') <> 0) and

         (AnsiCompareText(fext, '.3gp2') <> 0) and

         (AnsiCompareText(fext, '.3gpp') <> 0) and

         (AnsiCompareText(fext, '.m2ts') <> 0) then

        responseFailed

      else

      begin

 

        if FileExists(path) then

        begin

          try

            DeleteFile(path);

            responseOK;

          except

          on e:Exception do

            responseFailedException(e);

          end;

        end

 

        else

          responseFailed;

 

      end;

 

    finally

      CoUninitialize;

    end;

  end

 

  else

    MakeSimpleRestResponse(AResponseInfo, 404, 'Unknown path');

end;

 

procedure TMBRoseEmbRestServerThread.ManageGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo; elementCount: Integer);

var

  o: TJSONObject;

begin // GET

  if (elementCount = 1) and (CompareText(TRestServer.GetElement(ARequestInfo.Document, 1), 'version') = 0) then

  begin

    CoInitialize(nil);

    try

      AResponseInfo.ResponseNo := 200;

      AResponseInfo.ContentType := 'application/json';

      AResponseInfo.CharSet := 'utf-8';

 

      o := TJSONObject.Create;

      try

        o.AddPair('version', TJSONString.Create(Trendware.IOUtils.FileVersion.GetProgramVersionInfo(3)));

        o.AddPair('date', TJSONString.Create(Trendware.IOUtils.FileVersion.GetProgramVersionInfo(10)));

        o.AddPair('copyright', TJSONString.Create(Trendware.IOUtils.FileVersion.GetProgramVersionInfo(5)));

 

        AResponseInfo.ContentText := o.ToJSON;

      finally

        o.Free;

      end;

    finally

      CoUninitialize;

    end;

  end

 

  else…

 

Mvh

Sean

 

From: da...@googlegroups.com <da...@googlegroups.com> On Behalf Of Thomas Lassen
Sent: 16. juni 2025 12:34
To: DAPUG <da...@googlegroups.com>
Subject: [DAPUG] Nemmeste måde at opbygge et REST API i Delphi.

 

Hej Liste.

--

Trendware.Rest.ServerUtils.pas
Trendware.Rest.Server.pas

Brian Hansen

unread,
Jun 16, 2025, 2:38:38 PMJun 16
to da...@googlegroups.com

Hej Thomas

 

Jeg startede med REST API som ISAPI plugin til Microsoft IIS, men er nu gået 100% over på RAD Server (også på Microsoft IIS eller Apache), så får jeg en masse funktionalitet og sikkerhed med i løsningen.

 

Venlig hilsen

Brian Hansen

 

Brian Hansen Consulting ApS

Phone: (+45)30525308

https://brianhansenconsulting.dk

https://media.licdn.com/mpr/mpr/shrinknp_200_200/AAEAAQAAAAAAAAULAAAAJGExZGQ4ZTVkLWRiYTItNDU1My1iNWY1LWMzMjI2ZGYyNGZkZg.gif

 

Mangler du en Whistleblower løsning. Læs om vores løsning på sibilum.com

--

Bjarne Rasmussen

unread,
Jun 17, 2025, 1:38:28 AMJun 17
to DAPUG
Jeg vil da også lige kaste Daniele Tetis - DMVC Framework - med ind i puljen.
Det er open-source. Så ingen mønt er nødvendig for at komme i gang.

Det er super nemt at komme i gang med - og der er en hel det eksempler med, som du kan bruge til at lege med for ligesom at komme ind i hvordan frameworket fungerer.

Det skal dog siges -  at det bygger ovenpå INDY http serveren. Men den vil måske forsvinde i kommende versioner.
Frameworket bliver konstant vedligeholdt. Og der er mange brugere af det.



Med venlig hilsen

 

Bjarne Rasmussen

Udvikler

 

 

Microcom A/S

Samuel Morses Vej 3 | 8200 Aarhus | Tlf. +45 66 15 46 00 | www.microcom.dk



Sendt: 16. juni 2025 12:34
Til: DAPUG <da...@googlegroups.com>
Emne: [DAPUG] Nemmeste måde at opbygge et REST API i Delphi.

Vedel, Thomas

unread,
Jun 17, 2025, 2:42:02 AMJun 17
to da...@googlegroups.com
Hej Thomas

Hvis du har Enterprise eller Architect versionen af Delphi er RAD Server et rigtig godt valg!

Hvis du har Pro versionen ville jeg gå med XDATA som Jens og Glenn foreslår, hvis det gerne må koste lidt penge. Det er alle pengene værd.
Hvis det skal være gratis ville jeg gå med Delphi MVC.


Med venlig hilsen / Kind regards

 

Thomas Vedel

Software Developer

 

 

 


Fra: da...@googlegroups.com <da...@googlegroups.com> på vegne af Brian Hansen <br...@sibilum.com>
Sendt: 16. juni 2025 20:38
Til: da...@googlegroups.com <da...@googlegroups.com>
Emne: SV: [DAPUG] Nemmeste måde at opbygge et REST API i Delphi.
 
This email originated from outside of CGM. Please do not click links or open attachments unless you know the sender and know the content is safe.


Thomas Lassen

unread,
Jun 19, 2025, 9:30:00 AMJun 19
to da...@googlegroups.com
Kære alle (der har svaret)

Tak for de mange gode svar - nu følger de næste spørgsmål:

Vi har faktisk Enterprise-licensen, så jeg prøvede at få gang i RAD Server, fordi det jo følger med. Grundet det IT-sikkerhedsmæssige setup i vores organisation, er det lidt udfordrende at få op at køre vis-a-vis brugen af InterBase. Derfor spørger jeg om det er noget man er tvunget til at bruge, når man gerne vil bruge RAD Server? Helt konkret bliver man fx bedt om at angive en instans af en InterBase database, ligesom en InterBase service er nødt til at være aktiv i baggrunden. Yderligere forstår jeg ikke helt hvordan det fungerer med licensen: Hvis jeg skal lægge min kode ud på en server, skal jeg så køre under min licens, eller skal der en separat licens til?

DMVC Framework virker i modsætning til RAD Server lidt lettere at få op at køre, eller er der noget jeg har misforstået?

Med venlig hilsen
Thomas Lassen


Martin Banke Jensen

unread,
Jun 19, 2025, 4:31:37 PMJun 19
to da...@googlegroups.com
Hej Thomas.
Et svar, måske lidt på bagkant:
Jeg har engang brugt mORMot2 frameworket til noget lignende.
Det var ret nemt at få op at køre.

Jeg har ikke prøvet at kompilere/køre nedenståde ChatGPT' forslag, men det ser umiddelbart fornuftigt ud:

Vh
Martin

GlennKonnekt | Glenn Dufke

unread,
Jun 19, 2025, 5:31:27 PMJun 19
to da...@googlegroups.com
Hej Thomas,

InterBase er desværre et krav at have installeret når man bruger RAD Server, også selvom alt det man skal tilgå kommer fra fx en MSSQL database.

DMVC kræver ikke en specifik database bagvedm så du kan - via FireDAC, bygge oven på den database i har nu, hvis nødvendigt.

--------------------------------------------------------------------
Med venlig hilsen / Kind regards

Glenn Dufke
Embarcadero MVP - Building the next gen apps with Delphi
g...@gkon.dk
LinkedIn: www.linkedin.com/in/glenn-dufke-b3538a39

Confidentiality notice
This e-mail, including any attachment, may contain confidential and privileged information.
If you have received it by mistake, please notify us by e-mail and delete this e-mail and any attachment from your computer system immediately.
Thank you!

Fortrolighedserklæring
Denne e-mail og vedhæftede bilag kan indeholde fortrolige og beskyttede oplysninger.
Hvis De ved en fejl har modtaget denne e-mail, anmodes De venligst straks om at give afsenderen besked via e-mail og slette denne e-mail og bilag fra Deres system omgående.
Mange tak!
------ Original Message ------
From "Thomas Lassen" <lassen...@gmail.com>
Date 19/06/2025 15.29.43
Subject Re: [DAPUG] Nemmeste måde at opbygge et REST API i Delphi.

Vedel, Thomas

unread,
Jun 20, 2025, 2:54:06 AMJun 20
to da...@googlegroups.com
Blot en præcisering af Glenns svar:

RAD Server er internt afhængig af InterBase.
Du kan vælge en hvilken som helst database som grundlag for den forretningsløsning du laver med brug af RAD Server, og selve den løsning du laver, får ingen afhængigheder af InterBase.

Med venlig hilsen / Kind regards

 

Thomas Vedel

Software Developer

 

 

CompuGroup Medical Denmark A/S

Silovej 8 | DK-9900 Frederikshavn

 

thomas...@cgm.com

www.cgm.com


Fra: da...@googlegroups.com <da...@googlegroups.com> på vegne af GlennKonnekt | Glenn Dufke <g...@gkon.dk>
Sendt: 19. juni 2025 23:31
Til: da...@googlegroups.com <da...@googlegroups.com>
Emne: Re[2]: [DAPUG] Nemmeste måde at opbygge et REST API i Delphi.
 
Reply all
Reply to author
Forward
0 new messages