Search code examples
httpdelphifiremonkeyput

Delphi firemonkey HTTP Put body parameter


What is the correct way to write a stringstream using TIdHTTP.Put() in Delphi FireMonkey?

I have a PHP API (slim) like this:

// Update user
$app->put('/api/user/update/{id}', function(Request $request, Response $response){
    $id = $request->getAttribute('id');
    $username = $request->getParam('username');
    $password = $request->getParam('password');
    $nama = $request->getParam('nama');
    $alamat = $request->getParam('alamat');
    $jenis_kelamin = $request->getParam('jenis_kelamin');
    $foto = $request->getParam('foto');

    $sql = "UPDATE user SET
        username    = :username,
        password    = :password,
                nama        = :nama,
                alamat      = :alamat,
                jenis_kelamin   = :jenis_kelamin,
                foto        = :foto
            WHERE id = $id";

    try{
        // Get DB Object
        $db = new db();
        // Connect
        $db = $db->connect();

        $stmt = $db->prepare($sql);

        $stmt->bindParam(':username', $username);
        $stmt->bindParam(':password',  $password);
        $stmt->bindParam(':nama',      $nama);
        $stmt->bindParam(':alamat',      $alamat);
        $stmt->bindParam(':jenis_kelamin',    $jenis_kelamin);
        $stmt->bindParam(':foto',       $foto);

        $stmt->execute();

        echo '{"notice": {"text": "Customer Updated"}';

    } catch(PDOException $e){
        echo '{"error": {"text": '.$e->getMessage().'}';
    }
});

The procedure in Delphi for posting data via HTTP is like this:

procedure TForm3.updateexample;
var
  lHTTP: TIdHTTP;
  lParamList: TStringList;
  stream : TStringStream;
  mydata,json: string;

begin


 json := 'username='+edtusername.Text+
          'password='+edtpassword.Text+
          'nama='+edtnama.Text+
          'alamat='+edtalamat.Text+
          'jenis_kelamin='+cbbjkel.Selected.Text+
          'foto="'+edtalamat.text;

  stream := TStringStream.Create(json,Tencoding.UTF8);

  //create
  lHTTP := TIdHTTP.Create(nil);
  try

    mydata := lHTTP.put
      ('http://myweblablalbalbala/api/user/update/'+id,stream); 

    if Pos('Customer Updated', mydata) > 0 then
    begin
      ShowMessage('Update Succes');
    end
    else
      ShowMessage('update fail');
  finally
    lHTTP.Free;
    lParamList.Free;
  end;
end;

The code works, but after sending an update, the data changes from this (before the update):

{"id":"1","username":"iboy","password":"123456","nama":"ishak","alamat":"cikupa","jenis_kelamin":"l","foto":"iboy.jpg"}

to this (after the update):

{"id":"1","username":"","password":"","nama":"","alamat":"","jenis_kelamin":"","foto":""}

Can you help me? What is the correct way to post a stringstream via HTTP I Delphi?


Solution

  • You are not formatting your TStringstream data correctly. It is not even close to being JSON (despite your variable name). And you are also not setting the TIdHTTP.Request.ContentType property so the server knows what kind of data you are actually sending.

    If you read the Slim documentation, Slim supports the following media types out of the box:

    • application/x-www-form-urlencoded
    • application/json
    • application/xml & text/xml

    The data you are trying to send is closest to application/x-www-form-urlencoded. That is normally sent using TIdHTTP.Post() instead of TIdHTTP.Put(), by giving it a TStrings object of name=value pairs. Post() will format the values in the application/x-www-form-urlencoded format for you, and set the Request.ContentType property to match.

    Your PHP is expecting a PUT request instead of a POST request. Per the Slim documentation, you can actually send a POST request and make it act like a PUT request, by either:

    • including a _METHOD=PUT value in your data (application/x-www-form-urlencoded only)

    • including an X-HTTP-Method-Override: PUT HTTP request header (works with any media type).

    Try something more like this:

    procedure TForm3.UpdateExample;
    var
      lHTTP: TIdHTTP;
      lParamList: TStringList;
      lReply: string;
    begin
      lParamList := TStringList.Create;
      try
        lParamList.Add('username='+edtusername.Text);
        lParamList.Add('password='+edtpassword.Text);
        lParamList.Add('nama='+edtnama.Text);
        lParamList.Add('alamat='+edtalamat.Text);
        lParamList.Add('jenis_kelamin='+cbbjkel.Selected.Text);
        lParamList.Add('foto='+edtalamat.Text);
    
        lHTTP := TIdHTTP.Create(nil);
        try
    
          // use one of these, not both!
          lParamList.Add('_METHOD=PUT');
          lHTTP.Request.MethodOverride := 'PUT';
    
          lReply := lHTTP.Post('http://myweblablalbalbala/api/user/update/'+id, lParamList); 
    
          if Pos('Customer Updated', lReply) > 0 then
            ShowMessage('Update Success')
          else
            ShowMessage('Update Fail');
        finally
          lHTTP.Free;
        end;
      finally
        lParamList.Free;
      end;
    end;