Jump to content
Registration disabled at the moment Read more... ×

Stuart Clennett

Members
  • Content Count

    53
  • Joined

  • Last visited

  • Days Won

    1

Everything posted by Stuart Clennett

  1. Hi, I can see the MARS.OpenAPI.* units exist but I'm really not sure how to use them. I have a MARS server app and would like to provide OpenAPI JSON for consumption by other utils, like Swagger. 1. How do I set this up at the 'engine/application level, and 2. How do I provide the documentation for each resource/endpoint ? Thanks in advance.
  2. Stuart Clennett

    Connection Pooling

    Hello all, I am returning to MARS after some years away. I noticed that the new template application has a ServerConnectionPool data module. Has anyone implemented connection pooling with a single, central datamodule and FDConnection, with a separate TDataModule for handling requests? If so, could someone give me a heads up on the best ways to set up the initial TFDConnection component on the connection-pool datamodule and how to connect this to my queries in the request handling datamodule? Thanks Stuart
  3. Stuart Clennett

    Connection Pooling

    Neither in this case, I have done multi-tenancy before.
  4. Stuart Clennett

    Connection Pooling

    Hi mvanrijnen Thanks very much - that's a great idea. The FD instance is declared as `[Context] FD : TMarsFireDAC` in the Resource I assume. I have a TBaseResource that all other resources inherit from (apart from Token) - so this will be easy to implement 🙂 For connection pooling do I need to use FD.ConnectionDefName as I am loading FireDAC.MAIN_DB into the FDManager at start up (as per the MARSTemplate ), or will FD.Connection also provide pooling? Thanks, (it's been a while since I've done _any_ DB programming at all)
  5. Stuart Clennett

    Connection Pooling

    Hi Andrea, Sorry, it seems that I had this project from a while ago and I thought the server pooling was part of the template - my mistake. I am getting a little confused on how to set up a data module (created per request of course) that can pool connections, and respond to various end-points. I have the data-module already (inherits from TMARSFDDataModuleResource) and has most of my TFDQueries on there. I just need to have an instance created per endpoint request. Seems simple, but I can't figure it out. Is there a more comprehensive example somewhere? I see in the INI file created that we have FireDAC.MAIN_DB items commented out. Thanks Stuart
  6. Stuart Clennett

    Connection Pooling

    I have attached an image which may explain better. This is from the latest MARS Template; there is a ServerConnectionPool (TDataModule) that has a TFDConnection and is auto-created. There is a ServerMainDB TDataModule that contains an FDQuery; this datamodule is created once per request by each endpoint that needs it. I have just noticed that the FDQuery is attached to the TFDConnection at designtime, so maybe that is sufficient? Maybe I have overlooked the obvious.
  7. I've tried both Web and ISO installer. Win 11 VM (fresh install) with over 200Gb free on C drive. Windows defender turned off. Installers run as Admin. Installing for Windows development only (no iOS, Mac, Android or Linux). The installer gets about 50% of the way through and stops with this: The file is present and is not locked. Pressing Try Again immediately shows the same dialog. There was one attempt I made which I thought was working, but then stopped with the same message, but a different file: "LinuxPAServer23.0.tar.gz". When I press Cancel, this is the message I see: The retry option goes back to the start and eventually I get the same error message. Anyone got any ideas? Thanks.
  8. SOLVED My VM had an out of date Windows 11 installation (22H2), with no TPM module enabled. I created a fresh VM and installed the latest Win 11 Pro and the installation has gone through.
  9. Hi, Not sure if I'm on the right track here. I have a legacy database that has some images stored in blob fields in the database (I know). I'd like to be able to expose these images directly from the REST API, e.g. localhost:8080/rest/default/images/{id} I guess I have to set the Produces attribute to `image/jpeg` .. but what data type should I return? I've tried TBytes but although I get the bytes returned in Postman - web browsers don't load the image. Thanks
  10. Stuart Clennett

    Using an API endpoint as src for img tag ?

    Thanks Andrea - I'll look into that.
  11. Stuart Clennett

    Using an API endpoint as src for img tag ?

    Hi @Andrea Magni I implemented it using a simple base64 encoded string. Is there any benefit to using TStringWriter given that I may need the API to support web front ends written in a JS framework like Angular ? Thanks
  12. Hi, I am auto-renewing the JWT token on the server (as per the TokenAutoRenew demo). Having received the JWT token string from the server how do I update the client MARSToken with that value. The properties are read-only. Thanks
  13. HI, [Context] Request: TWebRequest; should be changed to [Context] Request: IMARSRequest; you'll need to include MARS.Core.RequestAndResponse.Interfaces in your uses clause. Regards
  14. Stuart Clennett

    Using an API endpoint as src for img tag ?

    So I'm back to this. I'm currently thinking of using Data-URLs to get the base64 image data and embed direcly into the Angular client app. (ref: https://css-tricks.com/data-uris/ & https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) Note that with the above TBytes solution I seem to get the response "[255, 0, 255, 0, 45, 56, 67 ..... ]" as text rather than raw bytes. The end point has the response type set as 'image/jpeg'
  15. Stuart Clennett

    Handling MultipartFormData

    @alejandro The demo does not save the file at all. You are required to implement that. However it is quite simple. For example, in the `StoreDataAndFile` method in `Server.Resources.pas` you could use a memory stream to access the Bytes and save to a file if SameText(LParam.FieldName, 'image') and LParam.IsFile then begin Result.FileSize := Length(LParam.AsFile.Bytes); Result.FileName := LParam.AsFile.FileName; // This will save the file lStream := TMemoryStream.Create; try lStream.Write(LParam.AsFile.Bytes, Length(LParam.AsFile.Bytes)); lStream.SaveToFile(TPath.Combine(C_RootPath, TPath.GetFileName(LParam.AsFile.FileName))); finally lStream.free; end; end In this instance, `C_RootPath` is just a folder on the server where uploaded files should be saved, but you could make this dynamic based on user info in the Token for example. Hope this helps
  16. Hi all, I've upgraded to MARS 1.4 and I'm hitting this compiler error on all my servers - including the MARSTemplate servers: [dcc32 Error] Server.Ignition.pas(86): E2010 Incompatible types: 'TBeforeHandleRequestProc' and 'Procedure' This is in response to the following: FEngine.BeforeHandleRequest := function (const AEngine: TMARSEngine; const AURL: TMARSURL; const ARequest: TWebRequest; const AResponse: TWebResponse; var Handled: Boolean ): Boolean begin Result := True; { code snip } end; which is in class constructor TServerEngine.CreateEngine. I'm not that great with anonymous methods & can't figure this one out. Thanks in advance,
  17. Thanks @Andrea Magni - I spotted the difference immediately after posting my question. Just going through and updating my servers now. Hope you're all safe & well.
  18. FIXED. The function signature now uses IMARSResponse and IMARSRequest from MARS.Core.ResponseAndRequest.Interfaces D'oh 🙂
  19. Hi, Is there anyway I can use a TFDQuery owned by a TDataModule with the resource result type TFDDataset (produces TMediaType.Application_JSON) ? At present MARS adds the FDQuery to the Activation context, so it tries to free it & it's already freed when the Datamodule is freed (as part of the resource cleanup) in the TMARSActivation.Invoke, e.g. function TAssessmentResource.GetAssessment(const id: string): TFDDataSet; begin // result := FData.qryAssessmentProperties; <-- results in Invalid Pointer Operation (FData is private DataModule) result := FD.CreateQuery(SQL_ASSESSMENT_PROPERTIES, nil, True, 'assessmentProperties'); TFDQuery(result).Params[0].AsString := id; end; The cause is as below: procedure TMARSActivation.Invoke; // [..snip..] begin try // [ ... invoke code ... ] finally // teardown phase FTeardownTime := TStopwatch.StartNew; if Assigned(FResourceInstance) then FResourceInstance.Free; //<-- datamodule & TFQuery freed here FreeContext; //<-- TFDQuery is in the current context so attempts to free here = Invalid Pointer Operation FTeardownTime.Stop; end; I'd rather not have to create my own JSON stream, but I'd like to have my DB logic encapsulated in a data module. Thanks Stuart
  20. Hi @Andrea Magni Ah brilliant, I wondered what "IsReference" meant 😄 Thanks again
  21. Stuart Clennett

    FireDAC Connections

    Hi, I'm looking at the TMARSFDDataModuleResource and I see that it has protected members `FD` (TMarsFireDAC) and `URL` (TMARSURL). In my descendant class both of these are `nil` references. Is there a way to use this? Reason is I'm trying to switch DB connections based on the server's own host URL. E.g. if it's accessed via localhost or 192.168.x.x then use the LOCAL_DB connection def, otherwise use PROD_DB Edit: Which also begs the question, where is the best place to call `FD.ConnectionDefName := MyConnectionDefName;` ? Thanks Stuart
  22. Stuart Clennett

    FireDAC Connections

    Hello Andrea, That's excellent, thank you very much for your detailed answer. I agree with you that the Connection attribute seems a much cleaner implementation and I will have a go at refactoring my project. Thanks again, Best wishes, Stuart
  23. Stuart Clennett

    FireDAC Connections

    Ah, figured it out. FEngine.BeforeHandleRequest := function (const AEngine: TMARSEngine; const AURL: TMARSURL; const ARequest: TWebRequest; const AResponse: TWebResponse; var Handled: Boolean): Boolean var App: TMARSApplication; begin Result := True; // skip favicon requests (browser) ... [snip] // Handle CORS and PreFlight ... [snip] // Get the default connection name based on the host URL if (pos('localhost', AUrl.URL) > 0) or (pos('192.168.', aUrl.URL) > 0) then cConnectionDefname := 'LOCAL_DB' else cConnectionDefName := 'MAIN_DB'; // apply to every application for App in AEngine.Applications.Values do App.Parameters.Values['FireDAC.ConnectionDefName'] := cConnectionDefName; end; So I get the default connection def name based on the URL. Then set the correct parameter for each hosted application. (My previous mistake was setting the `FireDAC.ConnectionDefName` parameter at the Engine level) If anyone can think of a better or more elegant way, please let me know. Thanks
×