Contents

Intro

Ive been asked questions about how to handle POST via kbmMW’s smart service based REST.

This blog post explains the typical POST variations, and how to handle them in kbmMW.

POST variants

A web/REST client can POST data in multiple ways:

  1. As value data in the path part of the URL
    eg. POST http://localhost/myservice/myfunction/10/20
  2. As key/value data in the query part of the URL
    eg. POST http://localhost/myservice/myfunction?arg1=10&arg2=20
  3. As FORM key/value data in the body.
    eg. POST http://localhost/myservice/myfunction
    and then body contains:
    name1=value1&name2=value2
  4. As XML or JSON data in the body.
    eg. POST http://localhost/myservice/myfunction
    and then body contains:
    {“name1″:”value1″,”name2″:”value2”}
  5. As Multipart body typically as part of a file upload.

You extract data in different ways depending on the way the client has chosen to send them.

  1. You use:
         [kbmMW_Rest('method:post, path: "myfunction/{value1}/{value2}"')]
         function MyFunction(
          [kbmMW_Rest('value:"{value1}"')] AValue1:integer;
          [kbmMW_Rest('value:"{value2}"')] AValue2:integer):string;
  2. You use:
    [kbmMW_Rest('method:post, path: "myfunction"')]
         function MyFunction(
          [kbmMW_Rest('value:"$value1"')] AValue1:integer;
          [kbmMW_Rest('value:"$value2"')] AValue2:integer):string;
  3. You use:
         [kbmMW_Rest('method:post, path: "myfunction"')]
         function MyFunction(
          [kbmMW_Rest('value:body')] ABody:string):string;
    

    and in MyFunction’s implementation:

    var
     qv:TkbmMWHTTPQueryValues; // Found in kbmMWHTTPUtils.pas
    begin
      qv:=TkbmMWHTTPQueryValues.Create;
      try
       qv.AsString:=ABody; // If the body is URL encoded you can use qv.AsEncodedString:=ABody
       value1:=qv.ValueByName['value1'];
       value2:=qv.ValueByName['value2'];
      finally
        qv.Free;
      end;
    end;
    
  4. There are multiple ways:
    1.  If the data is “known” you can define a class to receive the data. Eg.
        [kbmMW_Root('data',[mwrfIncludeOnlyTagged])]
        TData = class
        private
           FValue1:string;
           FValue2:string;
        public
           [kbmMW_Attribute('name1')]
           property Value1:string read FValue1 write FValue1;
      
           [kbmMW_Attribute('name2')]
           property Value2:string read FValue2 write FValue2;
        end;
      ...
           [kbmMW_Rest('method:post, path: "myfunction"')]
           function MyFunction([kbmMW_Rest('value: "body"')]const AData:TData):integer;
      

      An instance of AData will then be provided to the function MyFunction and automatically freed upon exit of MyFunction.

    2. If the data is “unknown” you can use a XML or JSON streamer. Eg.
      var
        on:TkbmMWONCustomObject;
      begin
        json:=TkbmMWJSONStreamer.Create;
        try
         on:=json.LoadFromUTF16String(ABody);
         if on.IsObject then
        begin
          value1:=TkbmMWONObject(on).AsString['name1'];
          value2:=TkbmMWONObject(on).AsString['name2'];
        end;
        finally
          json.Free;
        end;
      end;
  5. It is somewhat more complex to handle, but kbmMW contains a TkbmMWHTTPMultiParts class that can be used to decipher multipart data containing multipart boundaries.This time we first need to figure out if its actually a multipart body. Then we need to figure out whats the boundary identification between each part, and then we can start to split it up and handle each part separately.
         [kbmMW_Rest('method:post, path: "myfunction"')]
         function MyFunction:string;
    
    function TMyService.MyFunction:string;
    var
       i:integer;
       mp:TkbmMWHTTPMultiParts;
       p:TkbmMWHTTPMultiPart;
       f:TkbmMWHTTPMimeHeaderValueFields;
       helper:TkbmMWHTTPTransportStreamHelper;
       sFileName,
       sBoundary:string;
       fs:TFileStream;
    begin
       Result:='No data found';
    
       // First pick out content-type header field.
       helper:=TkbmMWHTTPTransportStreamHelper(RequestTransportStream.Helper);
       f:=helper.Header.ValueFields['Content-Type'];
       if f=nil then
          exit;
    
       // Check if boundary given. If so parse multiparts.
       sBoundary:=f.ValueByName['boundary'];
       if sBoundary<>'' then
       begin
          mp:=TkbmMWHTTPMultiParts.Create(RequestStream,sBoundary);
          try
            // Loop thru parts.
            for i:=0 to mp.Count-1 do
            begin
              // Check if file upload.
              p:=mp.Parts[i];
              f:=p.Headers.ValueFields['Content-Disposition'];
              sFileName:=f.ValueByName['filename'];
              if sFileName<>'' then
              begin
                 ForceDirectories('.\receivedfiles');
                 sFileName:='.\receivedfiles\'+sFileName;
                 DeleteFile(sFileName);
                 fs:=TFileStream.Create(sFileName,fmCreate+fmOpenWrite);
                 try
                   p.SaveToStream(fs);
                 finally
                   fs.Free;
                 end;
                 Result:='Thank you for the file '+sFileName;
              end;
            end;
          finally
            mp.Free;
          end;
         end;
    end;

Prologue

There are many more features in the kbmMW REST smart service. Some of them are explained in other blog posts in this “REST easy” serie, You may also want to check out the documentation section containing more than 600 pages of documentation by visiting our site at http://www.components4developers.com, and look for the kbmMW documentations section.

If you like this, please share the word about kbmMW wherever you can and feel free to link, like, share and copy the posts of this blog to where you find they could be useful.

Oh… and whats about that featured image? It’s the mail boxes in Denmark… In danish we call that “Post kasser”. Due to the internet, fewer and fewer of these are to be found around the landscape. The last 10 years around 85% of all post offices has disappeared. Instead local grocery shops handle snail mail with various success.

Loading

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.