Executing requests and result types
Once a request is configured, you execute it and collect the response in one of three shapes: text, a stream, or a file. Each shape has a matching execute method and a matching ResultType. Execution is asynchronous by default, so the call returns immediately and the response is delivered through a callback or event. This chapter explains the execution modes and the three result types, and how to chain one call into the next.
Synchronous and asynchronous execution
Async defaults to True: the execute method returns at once and the response arrives later in a callback or response event — the right choice for UI applications, where blocking the main thread would freeze the window. Set Async := False only in console tools or on a background thread; the executed request then already holds the response when the call returns.
procedure TForm1.ExecuteAsyncOrSync;
var
LExecuted: TTMSFNCRESTClientExecutedRequest;
begin
TMSFNCRESTClient1.Request.URL := 'https://jsonplaceholder.typicode.com/posts/1';
{ Async (the default, True) returns immediately; read the result in a
callback or response event. Keep this for UI applications. }
TMSFNCRESTClient1.Request.Async := True;
TMSFNCRESTClient1.ExecuteRequestWithResultString(
procedure(AResponseString: string)
begin
Memo1.Lines.Text := AResponseString;
end);
{ Async := False blocks until the response is in. The returned executed
request already holds the response, so no callback is needed. Use it
only off the main thread or in console/tool code. }
TMSFNCRESTClient1.Request.Async := False;
LExecuted := TMSFNCRESTClient1.ExecuteRequestWithResultString;
Memo1.Lines.Text := LExecuted.Response.ResponseString;
end;
Warning
Never use Async := False on the main UI thread. A slow or unreachable server will hang the application until the request times out.
Reading a text response
For JSON, XML, or any text payload, set ResultType := rrtString and call ExecuteRequestWithResultString. You can pass an inline callback that receives the body, in addition to the design-time event.
procedure TForm1.ReadStringResult;
begin
TMSFNCRESTClient1.Request.ResultType := rrtString;
TMSFNCRESTClient1.Request.URL := 'https://jsonplaceholder.typicode.com/posts/1';
{ Pass a callback directly to the execute method. It runs when the
response arrives, in addition to any OnRequestResponseStringRetrieved
handler assigned at design time. }
TMSFNCRESTClient1.ExecuteRequestWithResultString(
procedure(AResponseString: string)
begin
Memo1.Lines.Text := AResponseString;
end);
end;
Downloading into a stream
For binary content — images, archives, anything you keep in memory — set ResultType := rrtStream and call ExecuteRequestWithResultStream. The callback receives a TMemoryStream ready to load.
procedure TForm1.DownloadImage(const AImageURL: string);
begin
TMSFNCRESTClient1.Request.Clear;
TMSFNCRESTClient1.Request.ResultType := rrtStream;
TMSFNCRESTClient1.Request.URL := AImageURL;
{ The stream callback receives a TMemoryStream positioned at the start of
the response body, ready to load. }
TMSFNCRESTClient1.ExecuteRequestWithResultStream(
procedure(AResponseStream: TMemoryStream)
begin
Image1.Bitmap.LoadFromStream(AResponseStream);
end);
end;
Saving a response to a file
To write a download straight to disk without holding it in memory, set ResultType := rrtFile, set ResultFile to the destination path, and call ExecuteRequestWithResultFile. The callback reports the final path and byte count.
procedure TForm1.DownloadToFile;
begin
TMSFNCRESTClient1.Request.Clear;
TMSFNCRESTClient1.Request.ResultType := rrtFile;
{ ResultFile is the destination path the response body is written to. }
TMSFNCRESTClient1.Request.ResultFile := TPath.Combine(TPath.GetDownloadsPath, 'report.pdf');
TMSFNCRESTClient1.Request.URL := 'https://api.example.com/reports/42.pdf';
TMSFNCRESTClient1.ExecuteRequestWithResultFile(
procedure(AResponseFile: string; AResponseFileSize: Integer)
begin
ShowMessage(Format('Saved %d bytes to %s', [AResponseFileSize, AResponseFile]));
end);
end;
Note
The plain ExecuteRequest honours whatever ResultType you set on the request, and its OnRequestResponseRetrieved event exposes all three targets (string, stream, and file) at once. The typed ExecuteRequestWith... methods are shortcuts that also set the matching ResultType for you.
Chaining requests together
Real workflows often run one request based on another's result — fetch a record, then download an image it references. The example combines a text request and a stream request: it parses the first JSON response, extracts the thumbnailUrl, and feeds it into a second, stream-based call.
procedure TForm1.LoadPhotoThumbnail(APhotoID: Integer);
begin
{ Step 1 - a string request returns a JSON record. }
TMSFNCRESTClient1.Request.Clear;
TMSFNCRESTClient1.Request.ResultType := rrtString;
TMSFNCRESTClient1.Request.Host := 'https://jsonplaceholder.typicode.com';
TMSFNCRESTClient1.Request.Path := '/photos/' + IntToStr(APhotoID);
TMSFNCRESTClient1.ExecuteRequestWithResultString(
procedure(AResponseString: string)
var
LJSON: TJSONValue;
LImageURL: string;
begin
LJSON := TTMSFNCUtils.ParseJSON(AResponseString);
if not Assigned(LJSON) then
Exit;
try
LImageURL := TTMSFNCUtils.GetJSONProp(LJSON, 'thumbnailUrl');
{ Step 2 - feed the extracted URL into a stream request. }
if LImageURL <> '' then
begin
TMSFNCRESTClient1.Request.Clear;
TMSFNCRESTClient1.Request.ResultType := rrtStream;
TMSFNCRESTClient1.Request.URL := LImageURL;
TMSFNCRESTClient1.ExecuteRequestWithResultStream(
procedure(AResponseStream: TMemoryStream)
begin
Image1.Bitmap.LoadFromStream(AResponseStream);
end);
end;
finally
LJSON.Free;
end;
end);
end;
Common mistakes
- Result type and execute method disagree. Calling
ExecuteRequestWithResultStreamwhileResultTypeisrrtStringgives you an empty stream. Use the typed method (which sets the type) or setResultTypeto match. rrtFilewithoutResultFile. A file result with no destination path has nowhere to write. Always setResultFilefirst.- Reading the result on the wrong thread. With async execution, touch UI controls only inside the callback or response event, which run on the main thread — not right after the execute call returns.