Jump to content

ertank

Members
  • Content Count

    233
  • Joined

  • Last visited

Posts posted by ertank


  1. Hi,

     

    I didn't know about HeaderParam attribute.

        [POST, Path('test')]
        function Test([HeaderParam('x-api-key')] const ApiKey: string;
                      [BodyParam] const Body: string): string;

    Using above, I can check about ApiKey value in the function and use EMARSHttpException for returning a 404 error if necessary.

     

    I was searching a way to block a request with wrong x-api-key header value even before function code execution, but above approach is a solution, too.

     

    Thanks & Regards,

    Ertan


  2. Hi,

     

    If possible, I do not want to use existing "Authorization" header. I would like to allow access or block access depending on "x-api-key" header on each request.

     

    - x-api-key header missing: Block the request using 404

    - x-api-key header exists: Check in a method that it is correct. Allow only if correct, else block the request using 404

     

    Very basic example would be:

    Incoming request Header:
    x-api-key: my_own_key_data
    
    Incoming request Body:
    {"data":"Various json data. To be read as whole in a string"}

     

    Attached you can find is a sample postman request.

     

    Thanks & Regards,

    Ertan

    webhook_test.postman_collection.json


  3. Hello,

     

    I have a company that would like to send me some data over a webhook. They want me to provide them access information for an x-api-key header.

     

    I know that MARS uses Authorization header for secure access. I am not sure if it is possible to support x-api-key header for a specific use case.

     

    Any help is appreciated.

     

    Thanks & Regards,

    Ertan


  4. Hello,

     

    MARS file serve samples are based on fixed static data (ContentTypes demo). I have several endpoints serving dynamic data in ZIP files. When upload finishes on the server side, remaining temporary files are kept on disk. This become a problem on server systems in time.

     

    I would like to learn if it is possible to have MARS delete them automatically at the end of the communication.

     

    I will write my own thread but asking before just in case.

     

    Thanks & Regards,

    Ertan


  5. There maybe other codes shorter. Below should work on FMX and VCL for versions that has NetHTTPClient support.

    procedure TForm1.Button1Click(Sender: TObject);
    var
      MS: TMemoryStream;
      Response: IHTTPResponse;
    begin
      MS := TMemoryStream.Create();
      try
        try
          Response := NetHTTPClient1.Get('my_url', MS);
          if (Response.StatusCode < 200) or (Response.StatusCode > 299) then
          begin
            raise Exception.Create('Throw an exception or log response. Something is wrong');
          end;
        except
          on E: Exception do
          begin
            raise Exception.Create('Throw the exception or log it');
          end;
        end;
    
        //Do what you need to do with the memory stream
      finally
        MS.Free();
      end;
    end;

     

    I placed a component on the form itself for above example. If you need to create TNetHTTPClient instance by code, you will need following units in your uses

    uses
      System.Net.URLClient,
      System.Net.HttpClient,
      System.Net.HttpClientComponent;

     

    That code (having changed necessary parts) supposed to work on Windows, Linux, MacOS as it is without you to install any external libraries like OpenSSL libraries.

    If you get rid of error handling, you'll end up with a shorter version. This is something not suggested as you would know.

     

    I do not understand why you are after "shortest" code though.


  6. Hello,

     

    Your "complete" json is not valid. You should edit your post and fix it.

     

    There are more than one way to solve this. Below is an example with a lot of error checks.

    type
      TAnimal = record
        id: Integer;
        name: string;
      end;
      TAnimalList = TArray<TAnimal>;
    //-----------------------------------
    implementation
    //-----------------------------------
    uses
      System.JSON,
      System.Generics.Collections;
    
    const
      JsonString = '{"result":[{"animals":[{"id":1,"name":"pig"}]}]}';
    
    function ParseAnimalsJson(const Json: string; out AnimalList: TAnimalList): Boolean;
    var
      LTestJsonValue: TJSONValue;
      LJson: TJSONValue;
      LJsonArrayResult: TJSONArray;
      LJsonArrayAnimals: TJSONArray;
      I: Integer;
    begin
      LTestJsonValue := TJSONObject.ParseJSONValue(Json, False, False);
      if LTestJsonValue = nil then
      begin
        Exit(False);
      end;
    
      try
        LJson := LTestJsonValue.FindValue('result');
        if LJson = nil then
          Exit(False);
    
        if not (LJson is TJSONArray) then
          Exit(False);
    
        LJsonArrayResult := LJson as TJSONArray;
        if LJsonArrayResult.Count = 0 then
          Exit(False);
    
        LJson := LJsonArrayResult[0].FindValue('animals');
        if LJson = nil then
          Exit(False);
    
        if not (LJson is TJSONArray) then
          Exit(False);
    
        LJsonArrayAnimals := LJson as TJSONArray;
        SetLength(AnimalList, LJsonArrayAnimals.Count);
        for I := 0 to LJsonArrayAnimals.Count-1 do
        begin
          LJson := LJsonArrayAnimals[I].FindValue('id');
          if LJson = nil then Exit(False);
          AnimalList[I].id := LJson.AsType<Integer>;
    
          LJson := LJsonArrayAnimals[I].FindValue('name');
          if LJson = nil then Exit(False);
          AnimalList[I].name := LJson.AsType<string>;
        end;
      finally
        LTestJsonValue.Free();
      end;
      Result := True;
    end;
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
      List: TAnimalList;
    begin
      if ParseAnimalsJson(JsonString, List) then
      begin
        ShowMessage('Parse completed');
      end
      else
      begin
        ShowMessage('Parse failed!');
      end;
    end;

     


  7. Hello,

     

    There is a project that I have problem loading with Delphi 10.4.2. Main form is not loaded and Structure has below error line in it

    E2029 Declaration expected but end of file found at line 1 (1:1)

    I checked the DFM and PAS files using text editor and also hex editor. Both seems fine to me. Only thing is PAS file is UTF8 with BOM and that is not a problem at all. BOM bytes are also correct (ef bb bf).

     

    Unit file begins as following second line with a remark

    image.png.bbacd224128bb72bf87ac23d6effc05c.png

    DFM file begins as following

    image.png.ccef14885aee195b4488231d413e069d.png

     

    Project is from a private subversion repository. I checkout that repository as fresh in another directory and I still could not open it. But, another computer with Delphi 10.3.3 can load the project and its main form just fine.

     

    DFM size is 3,544,092 bytes

    PAS size is 414,839 bytes

     

    I didn't hear any limit about dfm/unit size. Providing these information just in case.

     

    My internet searches lead to actually corrupt files having similar errors and line number is not one. Wanted to ask in here with the hope that I am not the only person and there is a way to solve the problem.

     

    Thanks & Regards,

    Ertan


  8. Here is a link from official SQLite website https://www.sqlite.org/datatype3.html it says there is BLOB support.

    Here is another link from official SQLite website https://www.sqlite.org/changes.html you can find BLOB support is introduced with 2004-06-18 (3.0.0 alpha).

     

    Delphi already has TBlobField support https://docwiki.embarcadero.com/Libraries/Sydney/en/Data.DB.TBlobField


  9. Fiddler Telerik Classic (capable of decrypting https traffic) would be able to do that, too.

    It would be a local application and you won't be sending your credentials to a proxy server that you do not manage.

     

    If you are using TNetHTTPClient (or your choice of components do) you won't need any manual proxy setting. Just run Fiddler Telerik before you run your application that you would like to catch its traffic.

    If you are using TIdHTTP (or your choice of components do) you will need to manually set proxy to Your_Local_IP_Number:8888 for default settings.


  10. Having no code shared, I am just speculating that you update data while all 15 charts are visible on the screen.

    If that is the case, you might try to fill data while charts are hidden. You might want to fill your data between begin/end update statements

      Chart1.SeriesGroups.BeginUpdate();
      // data fill here
      Chart1.SeriesGroups.EndUpdate();

     

    It is just a wild guess and I am not sure if this is the problem. You should at least have detailed debug logging for yourself with milliseconds accuracy to understand if it is reading from the database is slow or filling up the chart data or something else.


  11. On 10/13/2022 at 3:09 AM, zsleo said:

    I have an app that uses TEdgeBrowser to display an XML file that points to a "very rich" XSL and DTD files that all reside in the same folder and sub-folder.

    Is it possible for you to convert these files into a single HTML and load it as a file?


  12. 7 hours ago, Remy Lebeau said:

    You can enumerate the TXMLDocument.Node.ChildNodes list, looking for any children IXMLNode entries whose IXMLNode.NodeType property is ntProcessingInstr

    Thank you. When I do that, I can find 'xml-stylesheet' node. But, its attribute list is empty. I could read NodeValue though. I used below code for testing.

    uses
      Xml.XMLDoc,
      Xml.XMLIntf;
    
    const
      XmlData = '<?xml version="1.0" encoding="UTF-8"?>' + sLineBreak +
                '<?xml-stylesheet type="text/xsl" href="xsl_for_this_xml.xslt"?>' + sLineBreak +
                '<DATA xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' + sLineBreak +
                '</DATA>';
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
      LXml: IXMLDocument;
      LNode: IXMLNode;
    begin
      LXml := NewXMLDocument();
      LXml.LoadFromXML(XmlData);
      LNode := LXml.ChildNodes.First;
      while LNode <> nil do
      begin
        if (LNode.NodeType = ntProcessingInstr) and (LNode.NodeName = 'xml-stylesheet') then
        begin
          if LNode.HasAttribute('type') then
          begin
            ShowMessage('type: ' + LNode.Attributes['type']);
          end;
    
          if LNode.HasAttribute('href') then
          begin
            ShowMessage('href: ' + LNode.Attributes['href']);
          end;
    
          ShowMessage('NodeValue: ' + LNode.NodeValue);
          Break;
        end;
        LNode := LNode.NextSibling;
      end;
    end;

    That only display message NodeValue: type="text/xsl" href="xsl_for_this_xml.xslt". This also leaves a small text parsing.


  13. When I test it, GET method redirects to URL https://qws.quartix.com/v2/api/auth and respond with "{"Message":"The requested resource does not support http method 'GET'."}" There is no 404 error.

     

    I have tried to use TRESTRequest and other relevant components in the past. I got a memory leak that had to be fixed by Embarcadero. After that incident, I directly communicate using HTTP component of my choice.

     

    You should have a swagger or postman document or a web link for explanation of endpoints. You also should have some test environment credentials in order to be able to build your integration. I could not see any publicly available API information. You probably need to apply for it.

     


  14. Hello,

     

    Is it possible to read XML processing instructions using TXMLDocument? Assuming XML I am trying to parse is as follows

    <?xml version="1.0" encoding="UTF-8"?>
    <?xml-stylesheet type="text/xsl" href="xsl_for_this_xml.xslt"?>
    <DATA xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    </DATA>

    I am trying to read "href" value in "xml-stylesheet".

     

    I will parse it as text if this is not possible to read using existing XML routines in Delphi.

     

    Thanks & Regards,

    Ertan

    • Like 1

  15. Hello,

     

    I am using Delphi 10.4.2

     

    I have a project that I developed about three years ago for a specific Android 5.1.1 device built in China. I do not remember what Delphi version I was using at that development time three years ago.

     

    Today, I need to do some modifications to that project. There is no problem compiling. When I try to debug run, I get error "Failure INSTALL_FAILED_OLDER_SDK" at deployment phase.

     

    When I check for min supported Android version is listed as Android 5.1 here

    https://docwiki.embarcadero.com/RADStudio/Sydney/en/Android_Devices_Supported_for_Application_Development

     

    I do not know if anything changed for Delphi 10.4.2 as I could not find a specific documentation about it.

     

    Is there anything I can do to fix this problem?

     

    Thanks & Regards,

    Ertan


  16. AFAIK, it is not common to have support for such parsing in text editor codes.

     

    BTW, what you are trying to do is not a very simple task. You probably need to build it yourself even if you find a source to use as a base. It takes time and a lot of corner case fixes for your database of choice. You should consider having per database parsing like one for SQLite another for SQL Server, etc.

     

    Also consider following examples. They are FirebirdSQL specific.

    WITH CTE
    AS (SELECT EXTRACT(WEEKDAY FROM ADATE) AS DAYOFWEEK, PAYMENTID, PAYMENTMETHODID, AVG(GENERALTOTALPRICE) GENERALTOTALPRICE
        FROM TRANSFERS
        WHERE STATIONID = 1 AND (PAYMENTMETHODID = 10 OR PAYMENTMETHODID = 20 OR PAYMENTMETHODID = 50 OR PAYMENTMETHODID = 60 OR PAYMENTMETHODID = 205) AND (TARIH >= '2022-01-01' AND TARIH <= '2022-01-31 23:59:59.999')
        GROUP BY 1, 2, 3)
    SELECT DAYOFWEEK, SUM(GENERALTOTALPRICE)
    FROM CTE
    GROUP BY 1
    
    UNION
    
    SELECT 7, SUM(GENERALTOTALPRICE)
    FROM CTE
    GROUP BY 1

     

    Another example;

    set term ^ ;
    execute block as
    begin
      if (not exists(select 1 from RDB$RELATION_FIELDS rf where rf.RDB$RELATION_NAME = 'POS' and rf.RDB$FIELD_NAME = 'AGROUP')) then
        execute statement 'alter table pos add agroup varchar(100);';
      if (not exists(select 1 from RDB$RELATION_FIELDS rf where rf.RDB$RELATION_NAME = 'FUEL' and rf.RDB$FIELD_NAME = 'AGROUP')) then
        execute statement 'alter table fuel add agroup varchar(100);';
      if (not exists(select 1 from RDB$RELATION_FIELDS rf where rf.RDB$RELATION_NAME = 'PAYMENT' and rf.RDB$FIELD_NAME = 'AGROUP')) then
        execute statement 'alter table payment add agroup varchar(100);';
    end^
    set term ; ^

     

    I do not know your user base but all these are valid SQL statements for FirebirdSQL and can be placed one after another, might also include "COMMIT" statements between which is another thing to control in your code if you are to parse and execute each identified block as its own.

     

    I did not check ZeosLib codebase. If they have any "parsing" and "identifying" SQL statement blocks. That would be a good starting point.

     

    Alternative is to force your users to use simple statements with default terminator at the end. Such SQL statements are pretty easy to parse.

×