Improved enum and set parameters handling in JSONRPC API

This commit is contained in:
Daniele Teti 2022-08-10 17:57:59 +02:00
parent de6e7960d7
commit f79f4722d9
10 changed files with 340 additions and 96 deletions

View File

@ -466,7 +466,7 @@ The current beta release is named 3.2.2-nitrogen. If you want to stay on the-edg
- ⚡New `TMVCRESTClient` implementation based on *Net components, the previous one was based on INDY Components (thanks to [João Antônio Duarte](https://github.com/joaoduarte19)).
- ⚡New! `MVCJSONRPCAllowGET` attribute allows a remote JSON-RPC published object, or a specific method, to be called using GET HTTP Verb as well as POST HTTP Verb. POST is always available, GET is available only if explicitly allowed. `IMVCJSONRPCExecutor` allows to specify which HTTP Verb to use when call the server JSON.RPC methods. The default verb can be injected in the constructor and each `ExecuteRequest`/`ExecuteNotification` allows to override od adhere to the instance default.
- ⚡New! `MVCJSONRPCAllowGET` attribute allows a remote JSON-RPC published object, or a specific method, to be called using GET HTTP Verb as well as POST HTTP Verb. POST is always available, GET is available only if explicitly allowed. `IMVCJSONRPCExecutor` allows to specify which HTTP Verb to use when call the server JSON-RPC methods. The default verb can be injected in the constructor and each `ExecuteRequest`/`ExecuteNotification` allows to override od adhere to the instance default.
- ⚡New! eLua server side view support added! The View engine requires Lua's dlls so it is not included in the main package but in a sampl project. Check `serversideviews_lua` sample.
@ -573,6 +573,8 @@ The current beta release is named 3.2.2-nitrogen. If you want to stay on the-edg
- ✅ Improved error handling for JSON-RPC APIs (Thanks to [David Moorhouse](https://github.com/fastbike)). More info [here](https://github.com/danieleteti/delphimvcframework/issues/538).
- ✅ Improved parameter handling for enum and set in JSON-RPC APIs.
- ⚡ New! Added `ActiveRecordConnectionRegistry.AddDefaultConnection(const aConnetionDefName: String)`. The connection definition **must** be known by FireDAC. This method simplifies the most common scenario shown below.
```delphi

View File

@ -38,6 +38,9 @@ uses
type
TEnumTest = (etValue1, etValue2, etValue3);
TSetOfEnumTest = set of TEnumTest;
[MVCNameCase(ncLowerCase)]
TPerson = class
private

View File

@ -69,6 +69,9 @@ type
procedure RaiseCustomException;
function RaiseGenericException(const ExceptionType: Integer): Integer;
function SaveObjectWithJSON(const WithJSON: TJsonObject): TJsonObject;
//enums and sets support
function PassingEnums(Value1: TEnumTest; Value2: TEnumTest): TEnumTest;
//records support
function SavePersonRec(PersonRec: TTestRec): TTestRec;
function GetPeopleRecDynArray: TTestRecDynArray;
@ -123,6 +126,18 @@ begin
end;
function TMyObject.PassingEnums(Value1, Value2: TEnumTest): TEnumTest;
begin
if Value1 = Value2 then
begin
Result := TEnumTest.ptEnumValue4;
end
else
begin
Result := TEnumTest.ptEnumValue3;
end;
end;
function TMyObject.EchoComplexArrayOfRecords(
PeopleList: TTestRecDynArray): TTestRecDynArray;
begin

View File

@ -29,6 +29,7 @@ var
begin
Writeln('** DMVCFramework Server ** build ' + DMVCFRAMEWORK_VERSION);
Writeln('JSON-RPC Server with Published Objects');
Writeln('Listening on port ', APort);
LServer := TIdHTTPWebBrokerBridge.Create(nil);
try

View File

@ -34,14 +34,13 @@ interface
uses
System.Classes,
Data.DB,
System.SysUtils,
jsondataobjects,
MVCFramework,
MVCFramework.Commons,
System.Rtti,
System.Generics.Collections,
MVCFramework.Serializer.Commons,
MVCFramework.Serializer.JsonDataObjects;
MVCFramework.Serializer.JsonDataObjects, System.SysUtils;
const
JSONRPC_VERSION = '2.0';
@ -878,6 +877,7 @@ begin
end;
procedure JSONDataValueToTValueParamEx(
const JSONSerializer: TMVCJsonDataObjectsSerializer;
const JSONDataValue: TJsonDataValueHelper;
const RTTIParameter: TRttiParameter;
var ParamValue: TValue;
@ -940,13 +940,34 @@ begin
end;
end
end;
tkSet:
begin
if JSONDataValue.Typ <> jdtString then
begin
RaiseDeSerializationError('Cannot deserialize type ' + RTTIParameter.ParamType.Name);
end;
I := StringToSet(
RTTIParameter.ParamType.Handle,
StringReplace(JSONDataValue.Value, ' ', '', [rfReplaceAll]));
TValue.Make(I, RTTIParameter.ParamType.Handle, ParamValue);
end;
tkEnumeration:
begin
if JSONDataValue.Typ <> jdtBool then
if JSONDataValue.Typ = jdtBool then
begin
raise EMVCJSONRPCInvalidRequest.Create(BuildDeclaration(RTTIParameter));
ParamValue := JSONDataValue.BoolValue;
end
else
begin
JSONSerializer.ParseStringAsTValueUsingMetadata(
JSONDataValue.Value,
RTTIParameter.ParamType.Handle,
'type ' + RTTIParameter.ParamType.Name,
RTTIParameter.ParamType.GetAttributes,
ParamValue
);
end;
ParamValue := JSONDataValue.BoolValue;
end;
tkInteger:
begin
@ -1594,6 +1615,18 @@ begin
lJSONResp := CreateError(lReqID, E.JSONRPCErrorCode, E.Message, E.JSONRPCErrorData);
LogE(Format('[JSON-RPC][CLS %s][ERR %d][MSG "%s"]', [E.ClassName, E.JSONRPCErrorCode, E.Message]));
end;
on ExDeSer: EMVCDeserializationException do
begin
ResponseStatus(400);
lJSONResp := CreateError(lReqID, JSONRPC_ERR_INVALID_REQUEST, ExDeSer.Message, ExDeSer.DetailedMessage);
LogE(Format('[JSON-RPC][CLS %s][ERR %d][MSG "%s"]', [ExDeSer.ClassName, JSONRPC_ERR_INVALID_REQUEST, ExDeSer.Message]));
end;
on ExSer: EMVCSerializationException do
begin
ResponseStatus(400);
lJSONResp := CreateError(lReqID, JSONRPC_ERR_INTERNAL_ERROR, ExSer.Message, ExSer.DetailedMessage);
LogE(Format('[JSON-RPC][CLS %s][ERR %d][MSG "%s"]', [ExSer.ClassName, JSONRPC_ERR_INTERNAL_ERROR, ExSer.Message]));
end;
on Ex: Exception do // use another name for exception variable, otherwise E is nil!!
begin
//lJSONResp := CreateError(lReqID, 0, Ex.Message);
@ -1608,7 +1641,7 @@ begin
try
if not lExceptionHandled then
begin
lJSONResp := CreateError(lReqID, 0, Ex.Message);
lJSONResp := CreateError(lReqID, 0, Ex.Message, Ex.ClassName);
end
else
begin
@ -1750,6 +1783,7 @@ begin
for I := 0 to lJSONParams.Count - 1 do
begin
JSONDataValueToTValueParamEx(
fSerializer,
lJSONParams[I],
lRTTIMethodParams[I],
lParamsArray[I],
@ -1765,6 +1799,7 @@ begin
for I := 0 to lJSONNamedParams.Count - 1 do
begin
JSONDataValueToTValueParamEx(
fSerializer,
GetJsonDataValueHelper(lJSONNamedParams, lRTTIMethodParams[I].Name.ToLower),
lRTTIMethodParams[I],
lParamsArray[I],

View File

@ -443,6 +443,7 @@ function ObjectDict(const OwnsValues: Boolean = True): IMVCObjectDictionary;
function GetPaginationMeta(const CurrPageNumber: UInt32; const CurrPageSize: UInt32;
const DefaultPageSize: UInt32; const URITemplate: string): TMVCStringDictionary;
procedure RaiseSerializationError(const Msg: string);
procedure RaiseDeSerializationError(const Msg: string);
implementation

View File

@ -70,6 +70,12 @@ type
function TryMapNullableFloat(var Value: TValue; const JSONDataObject: TJsonObject;
const AttribName: string): Boolean;
public
procedure ParseStringAsTValueUsingMetadata(
const AStringValue: String;
const DestinationTypeInfo: PTypeInfo;
const ExceptionHintString: String;
const AAttributes: TArray<TCustomAttribute>;
var AValue: TValue);
function JSONObjectToRecord<T: record >(const JSONObject: TJsonObject): T; overload;
function StrToRecord<T: record >(const AJSONString: String): T;
procedure JSONObjectToNestedRecordField(const JSONObject: TJsonObject; RecordFieldRTTIType: TRttiField;
@ -1424,84 +1430,90 @@ begin
jdtString:
begin
lValueTypeInfo := AValue.TypeInfo;
if (lValueTypeInfo = System.TypeInfo(TDate)) then
AValue := TValue.From<TDate>(ISODateToDate(AJSONObject[APropertyName].Value))
else if (lValueTypeInfo = System.TypeInfo(TDateTime)) then
AValue := TValue.From<TDateTime>(ISOTimeStampToDateTime(AJSONObject[APropertyName].Value))
else if (lValueTypeInfo = System.TypeInfo(TTime)) then
AValue := TValue.From<TTime>(ISOTimeToTime(AJSONObject[APropertyName].Value))
else if (AValue.Kind = tkRecord) and (lValueTypeInfo <> TypeInfo(TValue)) then { nullables }
begin
if lValueTypeInfo = TypeInfo(NullableString) then
begin
AValue := TValue.From<NullableString>(NullableString(AJSONObject[APropertyName].Value))
end
else if lValueTypeInfo = TypeInfo(NullableTDate) then
begin
AValue := TValue.From<NullableTDate>(NullableTDate(ISODateToDate(AJSONObject[APropertyName].Value)))
end
else if lValueTypeInfo = TypeInfo(NullableTDateTime) then
begin
AValue := TValue.From<NullableTDateTime>
(NullableTDateTime(ISOTimeStampToDateTime(AJSONObject[APropertyName].Value)))
end
else if lValueTypeInfo = TypeInfo(NullableTTime) then
begin
AValue := TValue.From<NullableTTime>(NullableTTime(ISOTimeToTime(AJSONObject[APropertyName].Value)))
end
else if lValueTypeInfo = TypeInfo(NullableTGUID) then
begin
AValue := TValue.From<NullableTGUID>(TMVCGuidHelper.StringToGUIDEx(AJSONObject[APropertyName].Value));
end
else
raise EMVCSerializationException.CreateFmt('Cannot deserialize property "%s" from string', [APropertyName]);
end
else if (AValue.Kind = tkEnumeration) then
begin
LEnumSerType := estEnumName;
LEnumMappedValues := nil;
if TMVCSerializerHelper.AttributeExists<MVCEnumSerializationAttribute>(ACustomAttributes, LEnumAsAttr) then
begin
LEnumSerType := LEnumAsAttr.SerializationType;
LEnumMappedValues := LEnumAsAttr.MappedValues;
end;
if LEnumSerType = estEnumName then
begin
TValue.Make(GetEnumValue(AValue.TypeInfo, AJSONObject[APropertyName].Value), AValue.TypeInfo, AValue)
end
else
begin
LMappedValueIndex := LEnumMappedValues.IndexOf(AJSONObject[APropertyName].Value);
if LMappedValueIndex < 0 then
raise EMVCSerializationException.CreateFmt('Cannot deserialize property "%s" from mapped values',
[APropertyName]);
TValue.Make(GetEnumValue(AValue.TypeInfo, GetEnumName(AValue.TypeInfo, LMappedValueIndex)),
AValue.TypeInfo, AValue)
end;
end
else if (AValue.Kind = tkInteger) and (TryStrToInt(AJSONObject[APropertyName].Value, lOutInteger)) then
begin
AValue := lOutInteger;
end
else if (AValue.Kind = tkInt64) and (TryStrToInt64(AJSONObject[APropertyName].Value, lOutInteger64)) then
begin
AValue := lOutInteger64;
end
else if lValueTypeInfo.Kind = tkSet then
begin
lInt := StringToSet(AValue.TypeInfo, StringReplace(AJSONObject[APropertyName].Value, ' ', '',
[rfReplaceAll]));
TValue.Make(lInt, AValue.TypeInfo, AValue);
end
else
begin
AValue := TValue.From<string>(AJSONObject[APropertyName].Value);
end;
ParseStringAsTValueUsingMetadata(
AJSONObject[APropertyName].Value,
AValue.TypeInfo,
'property ' + APropertyName,
ACustomAttributes,
AValue);
// lValueTypeInfo := AValue.TypeInfo;
// if (lValueTypeInfo = System.TypeInfo(TDate)) then
// AValue := TValue.From<TDate>(ISODateToDate(AJSONObject[APropertyName].Value))
//
// else if (lValueTypeInfo = System.TypeInfo(TDateTime)) then
// AValue := TValue.From<TDateTime>(ISOTimeStampToDateTime(AJSONObject[APropertyName].Value))
//
// else if (lValueTypeInfo = System.TypeInfo(TTime)) then
// AValue := TValue.From<TTime>(ISOTimeToTime(AJSONObject[APropertyName].Value))
// else if (AValue.Kind = tkRecord) and (lValueTypeInfo <> TypeInfo(TValue)) then { nullables }
// begin
// if lValueTypeInfo = TypeInfo(NullableString) then
// begin
// AValue := TValue.From<NullableString>(NullableString(AJSONObject[APropertyName].Value))
// end
// else if lValueTypeInfo = TypeInfo(NullableTDate) then
// begin
// AValue := TValue.From<NullableTDate>(NullableTDate(ISODateToDate(AJSONObject[APropertyName].Value)))
// end
// else if lValueTypeInfo = TypeInfo(NullableTDateTime) then
// begin
// AValue := TValue.From<NullableTDateTime>
// (NullableTDateTime(ISOTimeStampToDateTime(AJSONObject[APropertyName].Value)))
// end
// else if lValueTypeInfo = TypeInfo(NullableTTime) then
// begin
// AValue := TValue.From<NullableTTime>(NullableTTime(ISOTimeToTime(AJSONObject[APropertyName].Value)))
// end
// else if lValueTypeInfo = TypeInfo(NullableTGUID) then
// begin
// AValue := TValue.From<NullableTGUID>(TMVCGuidHelper.StringToGUIDEx(AJSONObject[APropertyName].Value));
// end
// else
// raise EMVCSerializationException.CreateFmt('Cannot deserialize property "%s" from string', [APropertyName]);
// end
// else if (AValue.Kind = tkEnumeration) then
// begin
// LEnumSerType := estEnumName;
// LEnumMappedValues := nil;
// if TMVCSerializerHelper.AttributeExists<MVCEnumSerializationAttribute>(ACustomAttributes, LEnumAsAttr) then
// begin
// LEnumSerType := LEnumAsAttr.SerializationType;
// LEnumMappedValues := LEnumAsAttr.MappedValues;
// end;
//
// if LEnumSerType = estEnumName then
// begin
// TValue.Make(GetEnumValue(AValue.TypeInfo, AJSONObject[APropertyName].Value), AValue.TypeInfo, AValue)
// end
// else
// begin
// LMappedValueIndex := LEnumMappedValues.IndexOf(AJSONObject[APropertyName].Value);
// if LMappedValueIndex < 0 then
// raise EMVCSerializationException.CreateFmt('Cannot deserialize property "%s" from mapped values',
// [APropertyName]);
//
// TValue.Make(GetEnumValue(AValue.TypeInfo, GetEnumName(AValue.TypeInfo, LMappedValueIndex)),
// AValue.TypeInfo, AValue)
// end;
// end
// else if (AValue.Kind = tkInteger) and (TryStrToInt(AJSONObject[APropertyName].Value, lOutInteger)) then
// begin
// AValue := lOutInteger;
// end
// else if (AValue.Kind = tkInt64) and (TryStrToInt64(AJSONObject[APropertyName].Value, lOutInteger64)) then
// begin
// AValue := lOutInteger64;
// end
// else if lValueTypeInfo.Kind = tkSet then
// begin
// lInt := StringToSet(AValue.TypeInfo, StringReplace(AJSONObject[APropertyName].Value, ' ', '',
// [rfReplaceAll]));
// TValue.Make(lInt, AValue.TypeInfo, AValue);
// end
// else
// begin
// AValue := TValue.From<string>(AJSONObject[APropertyName].Value);
// end;
end;
jdtInt:
@ -2760,6 +2772,109 @@ begin
Result := Parse<TJDOJsonObject>(AString);
end;
procedure TMVCJsonDataObjectsSerializer.ParseStringAsTValueUsingMetadata(
const AStringValue: String;
const DestinationTypeInfo: PTypeInfo;
const ExceptionHintString: String;
const AAttributes: TArray<TCustomAttribute>;
var AValue: TValue);
var
lValueTypeInfo: PTypeInfo;
LEnumSerType: TMVCEnumSerializationType;
LEnumAsAttr: MVCEnumSerializationAttribute;
LEnumMappedValues: TList<string>;
LMappedValueIndex: Integer;
lOutInteger: Integer;
lOutInteger64: Int64;
lInt: Integer;
begin
lValueTypeInfo := DestinationTypeInfo;
if (lValueTypeInfo = System.TypeInfo(TDate)) then
AValue := TValue.From<TDate>(ISODateToDate(AStringValue))
else if (lValueTypeInfo = System.TypeInfo(TDateTime)) then
AValue := TValue.From<TDateTime>(ISOTimeStampToDateTime(AStringValue))
else if (lValueTypeInfo = System.TypeInfo(TTime)) then
AValue := TValue.From<TTime>(ISOTimeToTime(AStringValue))
else if (lValueTypeInfo.Kind = tkRecord) and (lValueTypeInfo <> TypeInfo(TValue)) then { nullables }
begin
if lValueTypeInfo = TypeInfo(NullableString) then
begin
AValue := TValue.From<NullableString>(NullableString(AStringValue))
end
else if lValueTypeInfo = TypeInfo(NullableTDate) then
begin
AValue := TValue.From<NullableTDate>(NullableTDate(ISODateToDate(AStringValue)))
end
else if lValueTypeInfo = TypeInfo(NullableTDateTime) then
begin
AValue := TValue.From<NullableTDateTime>
(NullableTDateTime(ISOTimeStampToDateTime(AStringValue)))
end
else if lValueTypeInfo = TypeInfo(NullableTTime) then
begin
AValue := TValue.From<NullableTTime>(NullableTTime(ISOTimeToTime(AStringValue)))
end
else if lValueTypeInfo = TypeInfo(NullableTGUID) then
begin
AValue := TValue.From<NullableTGUID>(TMVCGuidHelper.StringToGUIDEx(AStringValue));
end
else
begin
raise EMVCSerializationException.CreateFmt('Cannot deserialize "%s" from string', [ExceptionHintString]);
end;
end
else if (lValueTypeInfo.Kind = tkEnumeration) then
begin
LEnumSerType := estEnumName;
LEnumMappedValues := nil;
if TMVCSerializerHelper.AttributeExists<MVCEnumSerializationAttribute>(AAttributes, LEnumAsAttr) then
begin
LEnumSerType := LEnumAsAttr.SerializationType;
LEnumMappedValues := LEnumAsAttr.MappedValues;
end;
if LEnumSerType = estEnumName then
begin
lOutInteger := GetEnumValue(lValueTypeInfo, AStringValue);
if lOutInteger = -1 then
begin
raise EMVCSerializationException.CreateFmt('Cannot deserialize "%s" from mapped values',
[ExceptionHintString]);
end;
TValue.Make(lOutInteger, lValueTypeInfo, AValue)
end
else
begin
LMappedValueIndex := LEnumMappedValues.IndexOf(AStringValue);
if LMappedValueIndex < 0 then
raise EMVCSerializationException.CreateFmt('Cannot deserialize "%s" from mapped values',
[ExceptionHintString]);
TValue.Make(GetEnumValue(lValueTypeInfo, GetEnumName(lValueTypeInfo, LMappedValueIndex)),
lValueTypeInfo, AValue)
end;
end
else if (lValueTypeInfo.Kind = tkInteger) and (TryStrToInt(AStringValue, lOutInteger)) then
begin
AValue := lOutInteger;
end
else if (lValueTypeInfo.Kind = tkInt64) and (TryStrToInt64(AStringValue, lOutInteger64)) then
begin
AValue := lOutInteger64;
end
else if lValueTypeInfo.Kind = tkSet then
begin
lInt := StringToSet(lValueTypeInfo, StringReplace(AStringValue, ' ', '', [rfReplaceAll]));
TValue.Make(lInt, lValueTypeInfo, AValue);
end
else
begin
AValue := TValue.From<string>(AStringValue);
end;
end;
procedure TMVCJsonDataObjectsSerializer.RecordToJsonObject(const ARecord: Pointer; const ARecordTypeInfo: PTypeInfo;
const AJSONObject: TJDOJsonObject; const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList);
begin

View File

@ -29,17 +29,21 @@ interface
uses
MVCFramework.Serializer.Commons, JsonDataObjects, MVCFramework.DuckTyping;
function NewJSONSerializer: IMVCJSONSerializer;
function StrToJSONObject(const aString: String; ARaiseExceptionOnError: Boolean = False): TJsonObject;
function StrToJSONArray(const aString: String; ARaiseExceptionOnError: Boolean = False): TJsonArray;
function WrapAsList(const AObject: TObject; AOwnsObject: Boolean = False): IMVCList;
implementation
uses
MVCFramework.Serializer.JsonDataObjects,
MVCFramework.Commons,
System.SysUtils;
System.SysUtils,
System.TypInfo;
function NewJSONSerializer: IMVCJSONSerializer;
begin

View File

@ -320,7 +320,6 @@ type
[Test]
procedure TestRequestToNotFoundMethod;
[Test]
[Category('this')]
procedure TestRequestWithParams_I_I_ret_I;
[Test]
procedure TestRequestWithNamedParams_I_I_ret_I;
@ -370,6 +369,17 @@ type
procedure TestRequest_Echo_ComplexRecords;
[Test]
procedure TestRequest_NoParams_DynamicArrayOfRecordAsResult;
//enum tests
[Test]
procedure TestEnum;
[Test]
procedure TestInvalidEnum;
//set tests
[Test]
procedure TestSet;
[Test]
procedure TestInvalidSet;
end;
[TestFixture]
@ -382,6 +392,7 @@ type
implementation
uses
System.TypInfo,
System.Math,
System.JSON,
MVCFramework.Serializer.Defaults,
@ -405,7 +416,7 @@ uses
Vcl.Graphics
{$ENDIF}
, TestConstsU, MVCFramework.Tests.Serializer.Entities,
MVCFramework.Logger, System.IOUtils;
MVCFramework.Logger, System.IOUtils, MVCFramework.Utils;
function GetServer: string;
begin
@ -2634,12 +2645,22 @@ begin
end;
end;
procedure TJSONRPCServerTest.TestEnum;
begin
var lRequest1: IJSONRPCRequest := TJSONRPCRequest.Create(1234, 'ProcessEnums');
lRequest1.Params.Add('etValue1');
lRequest1.Params.Add('etValue2');
var lResp := FExecutor2.ExecuteRequest(lRequest1);
Assert.AreEqual(
GetEnumValue(TypeInfo(TEnumTest), 'etValue2'),
GetEnumValue(TypeInfo(TEnumTest), lResp.Result.AsString)
);
end;
procedure TJSONRPCServerTest.TestHooks;
begin
var
lRequest1: IJSONRPCRequest := TJSONRPCRequest.Create(1234, 'request1');
var
lResp := FExecutor3.ExecuteRequest(lRequest1);
var lRequest1: IJSONRPCRequest := TJSONRPCRequest.Create(1234, 'request1');
var lResp := FExecutor3.ExecuteRequest(lRequest1);
Assert.areEqual('OnBeforeRoutingHook|OnBeforeCallHook|OnAfterCallHook',
FExecutor3.HTTPResponse.HeaderValue['x-history']);
end;
@ -2744,14 +2765,31 @@ end;
procedure TJSONRPCServerTest.TestHooksWhenOnBeforeRoutingHookRaisesError;
begin
var
lRequest1: IJSONRPCRequest := TJSONRPCRequest.Create(1234, 'error_OnBeforeRoutingHook');
var
lResp := FExecutor3.ExecuteRequest(lRequest1);
var lRequest1: IJSONRPCRequest := TJSONRPCRequest.Create(1234, 'error_OnBeforeRoutingHook');
var lResp := FExecutor3.ExecuteRequest(lRequest1);
Assert.isTrue(lResp.IsError, lResp.ToString(true));
Assert.areEqual(lResp.Error.ErrMessage, 'error_OnBeforeRoutingHook');
end;
procedure TJSONRPCServerTest.TestInvalidEnum;
begin
var lRequest1: IJSONRPCRequest := TJSONRPCRequest.Create(1234, 'ProcessEnums');
lRequest1.Params.Add('etValue1');
lRequest1.Params.Add('blabla'); //invalid enum value
var lResp := FExecutor2.ExecuteRequest(lRequest1);
Assert.IsTrue(lResp.IsError);
end;
procedure TJSONRPCServerTest.TestInvalidSet;
begin
var lRequest1: IJSONRPCRequest := TJSONRPCRequest.Create(1234, 'ProcessSets');
lRequest1.Params.Add('etValue1,blabla');
lRequest1.Params.Add('etValue3');
var lResp := FExecutor2.ExecuteRequest(lRequest1);
var l := lResp.AsJSONString;
Assert.IsTrue(lResp.IsError);
end;
procedure TJSONRPCServerTest.TestNotificationWhichRaisesError;
var
lReq: IJSONRPCNotification;
@ -3143,6 +3181,16 @@ begin
Assert.areEqual('DanieleDanieleDanieleDaniele', lRPCResp.Result.AsString);
end;
procedure TJSONRPCServerTest.TestSet;
begin
var lRequest1: IJSONRPCRequest := TJSONRPCRequest.Create(1234, 'ProcessSets');
lRequest1.Params.Add('etValue1,etValue2');
lRequest1.Params.Add('etValue3');
var lResp := FExecutor2.ExecuteRequest(lRequest1);
var l := lResp.AsJSONString;
Assert.AreEqual('etValue1,etValue2,etValue3', lResp.Result.AsString);
end;
{ TJSONRPCServerWithGETTest }
procedure TJSONRPCServerWithGETTest.InitExecutors;

View File

@ -44,6 +44,14 @@ type
[MVCInheritable]
function AddTimeToDateTime(aDateTime: TDateTime; aTime: TTime): TDateTime;
//enums support
[MVCInheritable]
function ProcessEnums(Value1: TEnumTest; Value2: TEnumTest): TEnumTest;
//sets support
[MVCInheritable]
function ProcessSets(Value1: TSetOfEnumTest; Value2: TEnumTest): TSetOfEnumTest;
//records support
[MVCInheritable]
function GetSingleRecord: TSimpleRecord;
@ -222,6 +230,18 @@ begin
Self.ClassName;
end;
function TTestJSONRPCClass.ProcessEnums(Value1, Value2: TEnumTest): TEnumTest;
begin
Result := TEnumTest((Ord(Value1) + Ord(Value2)) mod 3);
end;
function TTestJSONRPCClass.ProcessSets(Value1: TSetOfEnumTest;
Value2: TEnumTest): TSetOfEnumTest;
begin
Include(Value1, Value2);
Result := Value1;
end;
function TTestJSONRPCClass.Subtract(Value1, Value2: Int64): Integer;
begin
Result := Value1 - Value2;