Skip to content

Instantly share code, notes, and snippets.

@lzva
Created May 11, 2024 21:20
Show Gist options
  • Save lzva/4756328024ea8cde7de1110105f11601 to your computer and use it in GitHub Desktop.
Save lzva/4756328024ea8cde7de1110105f11601 to your computer and use it in GitHub Desktop.
Testing ways of sending variable inputs
program TestCallInBody;
{$APPTYPE CONSOLE}
uses
Windows,
mormot.core.variants,
mormot.core.interfaces,
mormot.rest.core,
mormot.rest.memserver,
mormot.rest.http.server,
mormot.rest.server,
mormot.soa.core,
mormot.core.json,
mormot.core.os,
mormot.core.data,
mormot.net.client
;
type
ITest = interface(IInvokable)
['{20B99698-D35A-43DD-A993-3A57AB40C302}']
function A(const Vars: Variant): TServiceCustomAnswer;
function B(const Idee, Udoo: Integer): TServiceCustomAnswer;
function C(const _AllInputAs: Variant): TServiceCustomAnswer;
end;
TTest = class(TInterfacedObject, ITest)
public
function A(const Vars: Variant): TServiceCustomAnswer;
function B(const Idee, Udoo: Integer): TServiceCustomAnswer;
function C(const _AllInputAs: Variant): TServiceCustomAnswer;
end;
THandlerContainer = class
function HandleBeforeURI(Ctxt: TRestServerURIContext): Boolean;
end;
var
U_InBody: String;
function GetInputParams: UTF8String;
begin
// outgoing Json variant must be retained by callee, otherwise DV will point
// to invalid data because variant gets auto-freed
if ServiceRunningRequest.Method = mPOST
then Result := _Json(U_InBody, [dvoIsObject])
else Result := ServiceRunningRequest.GetInputAsTDocVariant([], nil);
end;
function TTest.A(const Vars: Variant): TServiceCustomAnswer;
var
DV: TDocVariantData;
LIdx: Integer;
begin
DV := _DV(Vars);
Writeln(' Vars = ' + string(Vars));
if not DV.IsArray then
for LIdx := 0 to DV.Count - 1 do
Writeln(' ' + String(DV.Names[LIdx]) + ' = ' + String(DV.Value[LIdx]));
Result.Status := 200;
Result.Header := TEXT_CONTENT_TYPE_HEADER;
Result.Content := _Json(Vars, [dvoIsObject])
end;
function TTest.B(const Idee, Udoo: Integer): TServiceCustomAnswer;
begin
Result.Status := 200;
Result.Header := TEXT_CONTENT_TYPE_HEADER;
Result.Content := GetInputParams;
end;
function TTest.C(const _AllInputAs: Variant): TServiceCustomAnswer;
var
DV: TDocVariantData;
LIdx: Integer;
begin
DV := _DV(_AllInputAs);
Writeln(' _AllInputAs = ' + string(_AllInputAs));
for LIdx := 0 to DV.Count - 1 do
Writeln(' ' + String(DV.Names[LIdx]) + ' = ' + String(DV.Value[LIdx]));
Result.Status := 200;
Result.Header := TEXT_CONTENT_TYPE_HEADER;
Result.Content := _AllInputAs;
end;
function THandlerContainer.HandleBeforeURI(Ctxt: TRestServerURIContext): Boolean;
begin
Result := True;
if Ctxt.Method = mPOST then
begin
// because ServiceRunningRequest.Call.InBody is consumed
U_InBody := Ctxt.call.InBody;
UniqueString(U_InBody);
end;
end;
procedure Check(const Put, Expect, Got: String);
begin
WriteLn(' Put: ' + Put);
WriteLn(' Got: ' + Got);
if Expect <> Got
then WriteLn('= unexpected')
else WriteLn('= OK, as expected');
end;
var
LWebServer: TRestHttpServer;
LRestServer: TRestServerFullMemory;
LContainer: THandlerContainer;
const
CJSON_DOTTED = '{"Vars":{"Abc":123,"Def":321}}';
CJSON_DOTTED_REPLY = '{"Abc":123,"Def":321}';
CJSON_DOTTED_URI = 'Vars={Abc=123,Def=321}';
CJSON = '{"Idee":123,"Idoo":321,"Icee":775}';
CJSON_URI = 'Idee=123&Idoo=321&Icee=775';
CJSON3 = '{"Idee":{"Abc":123,"Def":222},"Idoo":321}';
begin
TInterfaceFactory.RegisterInterfaces([TypeInfo(ITest)]);
LContainer := THandlerContainer.Create;
LRestServer := TRestServerFullMemory.Create('API');
LRestServer.ServicesRouting := TRestServerRoutingRest;
LRestServer.OnBeforeURI := LContainer.HandleBeforeURI;
LRestServer.ServiceDefine(TTest, [ITest], sicShared);
LWebServer := TRestHttpServer.Create('8080', [LRestServer], '+', useHttpSocket, 1);
{$message 'this works but dont like having to use vars object'}
WriteLn; WriteLn('> function A(const Vars: Variant): TServiceCustomAnswer;');
WriteLn('> Post params as sub-properies');
Check(CJSON_DOTTED, CJSON_DOTTED_REPLY, TWinHttp.Post('http://localhost:8080/API/Test.A', CJSON_DOTTED));
WriteLn; WriteLn('> Get params as sub-properies');
Check(CJSON_DOTTED_URI, CJSON_DOTTED_REPLY, TWinHttp.Get('http://localhost:8080/API/Test.A?' + CJSON_DOTTED_URI));
WriteLn;
{$message 'this also works and is easy with overriding but doesnt express intent'}
WriteLn; WriteLn('> function B(const Idee, Udoo: Integer): TServiceCustomAnswer;');
WriteLn('> Post params via copy of call.InBody');
Check(CJSON, CJSON, TWinHttp.Post('http://localhost:8080/API/Test.B', CJSON));
WriteLn; WriteLn('> Get params via ServiceRunningRequest.GetInputAsTDocVariant');
Check(CJSON_DOTTED_URI, CJSON_DOTTED, TWinHttp.Get('http://localhost:8080/API/Test.B?' + CJSON_DOTTED_URI));
WriteLn;
{$message 'proposed new way to define unknown params'}
// procedure Abc(const _AllInputAs: Variant); -- _AllInputAs contains docvariant with parsed inputs for both GET and POST
// procedure Abc(const _AllInputAs: UTF8String); -- _AllInputAs would contain post body or uri params as text
WriteLn; WriteLn('> function C(const _AllInputAs: Variant): TServiceCustomAnswer;');
WriteLn('> Post to interface with magic param name _AllInputAs');
Check(CJSON3, CJSON3, TWinHttp.Post('http://localhost:8080/API/Test.C', CJSON3));
WriteLn; WriteLn('> Get from interface with magic param name _AllInputAs');
Check(CJSON_URI, CJSON, TWinHttp.Get('http://localhost:8080/API/Test.C?' + CJSON_URI));
LWebServer.Free;
LRestServer.Free;
LContainer.Free;
WriteLn; WriteLn; WriteLn('Sqeeze a key when done');
Readln;
end.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment