diff --git a/sources/MVCFramework.DataSet.Utils.pas b/sources/MVCFramework.DataSet.Utils.pas index 7f83321d..10fd2ad5 100644 --- a/sources/MVCFramework.DataSet.Utils.pas +++ b/sources/MVCFramework.DataSet.Utils.pas @@ -37,6 +37,7 @@ uses JsonDataObjects, MVCFramework.Commons, MVCFramework.Serializer.Commons, + MVCFramework.RESTClient.Intf, MVCFramework.RESTClient; type @@ -132,14 +133,14 @@ type type TMVCAPIBinderItem = class private - fRESTClient: TRESTClient; + fRESTClient: IMVCRESTClient; fDataSet: TDataSet; fURI: string; fPrimaryKeyNAme: string; fLoading: boolean; - procedure ShowError(const AResponse: IRESTResponse); + procedure ShowError(const AResponse: IMVCRESTResponse); public - constructor Create(const aRESTClient: TRESTClient; const ADataSet: TDataSet; + constructor Create(const aRESTClient: IMVCRESTClient; const ADataSet: TDataSet; const aURI, aPrimaryKeyName: string); destructor Destroy; override; procedure HookBeforePost(DataSet: TDataSet); @@ -149,12 +150,12 @@ type // procedure HookBeforeRowRequest(DataSet: TFDDataSet); end; private - fRESTClient: TRESTClient; + fRESTClient: IMVCRESTClient; protected fItems: TObjectList; public - constructor Create(const aRESTClient: TRESTClient); + constructor Create(const aRESTClient: IMVCRESTClient); destructor Destroy; override; procedure BindDataSetToAPI(const ADataSet: TDataSet; const aURI: string; const aPrimaryKeyName: string); end; @@ -597,7 +598,7 @@ begin fItems.Add(TMVCAPIBinderItem.Create(fRESTClient, ADataSet, aURI, aPrimaryKeyName)); end; -constructor TMVCAPIBinder.Create(const aRESTClient: TRESTClient); +constructor TMVCAPIBinder.Create(const aRESTClient: IMVCRESTClient); begin inherited Create; fItems := TObjectList.Create(true); @@ -612,7 +613,7 @@ end; { TMVCAPIBinder.TMVCAPIBinderItem } -constructor TMVCAPIBinder.TMVCAPIBinderItem.Create(const aRESTClient: TRESTClient; const ADataSet: TDataSet; +constructor TMVCAPIBinder.TMVCAPIBinderItem.Create(const aRESTClient: IMVCRESTClient; const ADataSet: TDataSet; const aURI, aPrimaryKeyName: string); begin inherited Create; @@ -640,18 +641,18 @@ end; procedure TMVCAPIBinder.TMVCAPIBinderItem.HookAfterOpen(DataSet: TDataSet); var - Res: IRESTResponse; + Res: IMVCRESTResponse; lData: TJSONObject; begin // this a simple sychronous request... - Res := fRESTClient.doGET(fURI, []); - if Res.HasError then + Res := fRESTClient.Get(fURI); + if Res.Success then begin ShowError(Res); end; - lData := StrToJSONObject(Res.BodyAsString); + lData := StrToJSONObject(Res.Content); try DataSet.DisableControls; try @@ -669,11 +670,11 @@ end; procedure TMVCAPIBinder.TMVCAPIBinderItem.HookBeforeDelete(DataSet: TDataSet); var - Res: IRESTResponse; + Res: IMVCRESTResponse; begin if DataSet.State = dsBrowse then Res := fRESTClient.DataSetDelete(fURI, DataSet.FieldByName(fPrimaryKeyNAme).AsString); - if not(Res.ResponseCode in [200]) then + if not(Res.StatusCode in [200]) then begin ShowError(Res); end; @@ -681,7 +682,7 @@ end; procedure TMVCAPIBinder.TMVCAPIBinderItem.HookBeforePost(DataSet: TDataSet); var - lRes: IRESTResponse; + lRes: IMVCRESTResponse; lLastID: Integer; begin if not fLoading then @@ -694,9 +695,9 @@ begin else begin lLastID := fDataSet.FieldByName(fPrimaryKeyNAme).AsInteger; - lRes := fRESTClient.DataSetUpdate(fURI, DataSet, lLastID.ToString); + lRes := fRESTClient.DataSetUpdate(fURI, lLastID.ToString, DataSet); end; - if not(lRes.ResponseCode in [200, 201]) then + if not(lRes.StatusCode in [200, 201]) then begin ShowError(lRes); end @@ -717,19 +718,13 @@ begin DataSet.Open; end; -procedure TMVCAPIBinder.TMVCAPIBinderItem.ShowError(const AResponse: IRESTResponse); +procedure TMVCAPIBinder.TMVCAPIBinderItem.ShowError(const AResponse: IMVCRESTResponse); begin - if AResponse.HasError then + if not AResponse.Success then raise EMVCException.Create( - AResponse.Error.ExceptionMessage + sLineBreak + - AResponse.Error.ExceptionClassname) + AResponse.StatusCode.ToString + ': ' + AResponse.StatusText + sLineBreak + AResponse.Content) else - raise EMVCException.Create(AResponse.BodyAsString); - // else - // MessageDlg( - // AResponse.ResponseCode.ToString + ': ' + AResponse.ResponseText + sLineBreak + - // AResponse.BodyAsString, - // mtError, [mbOK], 0); + raise EMVCException.Create(AResponse.Content); end; end. diff --git a/sources/MVCFramework.RESTClient.Commons.pas b/sources/MVCFramework.RESTClient.Commons.pas index 7bdd74df..c9ecdc74 100644 --- a/sources/MVCFramework.RESTClient.Commons.pas +++ b/sources/MVCFramework.RESTClient.Commons.pas @@ -34,7 +34,8 @@ interface uses System.NetEncoding, System.SysUtils, - System.Classes; + System.Classes, + MVCFramework.Commons; type @@ -73,6 +74,8 @@ type TMVCRESTClientConsts = record public const DEFAULT_ACCEPT_ENCODING = 'gzip,deflate'; + DEFAULT_ACCEPT = TMVCMediaType.APPLICATION_JSON + ', ' + TMVCMediaType.TEXT_PLAIN + ', ' + TMVCMediaType.TEXT_HTML; + DEFAULT_USER_AGENT = 'DelphiMVCFramework RESTClient/' + DMVCFRAMEWORK_VERSION; DEFAULT_FILE_NAME = 'file'; AUTHORIZATION_HEADER = 'Authorization'; BASIC_AUTH_PREFIX = 'Basic '; @@ -91,7 +94,6 @@ implementation uses IdCompressorZLib, System.ZLib, - MVCFramework.Commons, System.Net.Mime; { TMVCRESTParam } diff --git a/sources/MVCFramework.RESTClient.pas b/sources/MVCFramework.RESTClient.pas index 9e2d71b9..d2a94d4b 100644 --- a/sources/MVCFramework.RESTClient.pas +++ b/sources/MVCFramework.RESTClient.pas @@ -77,7 +77,12 @@ type fHTTPClient: THTTPClient; fBaseURL: string; fResource: string; - fInternalContentType: string; + + fAccept: string; + fAcceptCharset: string; + fAcceptEncoding: string; + fUserAgent: string; + fContentType: string; fProxySettings: TProxySettings; fParameters: TList; fRawBody: TStringStream; @@ -96,8 +101,8 @@ type procedure DoConvertMVCPathParamsToRESTParams(var aURL: string); procedure DoApplyPathParams(var aURL: string); procedure DoApplyQueryParams(var aURL: string); - procedure DoApplyHeaders; procedure DoApplyCookies(const aURL: string); + procedure DoApplyHeaders; procedure DoEncodeURL(var aURL: string); procedure DoPrepareBodyRequest(var aBodyStream: TStream); @@ -127,8 +132,6 @@ type function SecureProtocols(const aSecureProtocols: THTTPSecureProtocols): IMVCRESTClient; overload; function SecureProtocols: THTTPSecureProtocols; overload; {$ENDIF} - function UserAgent(const aUserAgent: string): IMVCRESTClient; overload; - function UserAgent: string; overload; /// /// Clears all parameters (headers, body, path params and query params). This method is executed after each @@ -233,6 +236,8 @@ type function HandleRedirects: Boolean; overload; function MaxRedirects(const aMaxRedirects: Integer): IMVCRESTClient; overload; function MaxRedirects: Integer; overload; + function UserAgent(const aUserAgent: string): IMVCRESTClient; overload; + function UserAgent: string; overload; function Resource(const aResource: string): IMVCRESTClient; overload; function Resource: string; overload; @@ -433,32 +438,35 @@ uses function TMVCRESTClient.Accept: string; begin - Result := HeaderValue(sAccept); + Result := fAccept; end; function TMVCRESTClient.Accept(const aAccept: string): IMVCRESTClient; begin - Result := AddHeader(sAccept, aAccept); + Result := Self; + fAccept := aAccept; end; function TMVCRESTClient.AcceptCharset: string; begin - Result := HeaderValue(sAcceptCharSet); + Result := fAcceptCharset; end; function TMVCRESTClient.AcceptCharset(const aAcceptCharset: string): IMVCRESTClient; begin - Result := AddHeader(sAcceptCharset, aAcceptCharset); + Result := Self; + fAcceptCharset := aAcceptCharset; end; function TMVCRESTClient.AcceptEncoding(const aAcceptEncoding: string): IMVCRESTClient; begin - Result := AddHeader(sAcceptEncoding, aAcceptEncoding); + Result := Self; + fAcceptEncoding := aAcceptEncoding; end; function TMVCRESTClient.AcceptEncoding: string; begin - Result := HeaderValue(sAcceptEncoding); + Result := fAcceptEncoding; end; function TMVCRESTClient.AddBody(const aBody: string; const aContentType: string): IMVCRESTClient; @@ -701,7 +709,7 @@ begin Result := Self; ClearParameters(TMVCRESTParamType.FormURLEncoded); - fInternalContentType := ''; + fContentType := ''; end; function TMVCRESTClient.ClearCookies: IMVCRESTClient; @@ -756,6 +764,10 @@ begin inherited Create; fHTTPClient := THTTPClient.Create; + fHTTPClient.HandleRedirects := True; + fHTTPClient.MaxRedirects := CHTTPDefMaxRedirects; + fHTTPClient.SecureProtocols := CHTTPDefSecureProtocols; + fParameters := TList.Create; fRawBody := TStringStream.Create; fBodyFormData := nil; @@ -765,6 +777,11 @@ begin fBaseURL := ''; fResource := ''; + fAccept := TMVCRESTClientConsts.DEFAULT_ACCEPT; + fAcceptCharset := ''; + fAcceptEncoding := TMVCRESTClientConsts.DEFAULT_ACCEPT_ENCODING; + fUserAgent := TMVCRESTClientConsts.DEFAULT_USER_AGENT; + fContentType := ''; end; function TMVCRESTClient.DataSetDelete(const aResource, aKeyValue: string): IMVCRESTResponse; @@ -845,6 +862,10 @@ begin fHTTPClient.CustomHeaders[lParam.Name] := lParam.Value; end; end; + fHTTPClient.Accept := fAccept; + fHTTPClient.AcceptCharSet := fAcceptCharset; + fHTTPClient.AcceptEncoding := fAcceptEncoding; + fHTTPClient.ContentType := fContentType; end; procedure TMVCRESTClient.DoApplyPathParams(var aURL: string); @@ -914,13 +935,12 @@ var lValue: string; lBody: string; begin - SplitContentMediaTypeAndCharset(fInternalContentType, lContentType, lContentCharset); + SplitContentMediaTypeAndCharset(fContentType, lContentType, lContentCharset); if SameText(lContentType, TMVCMediaType.MULTIPART_FORM_DATA) then begin aBodyStream := GetBodyFormData.Stream; SetContentType(GetBodyFormData.MimeTypeHeader); - fHTTPClient.CustHeaders[sContentType] := GetBodyFormData.MimeTypeHeader; end else if SameText(lContentType, TMVCMediaType.APPLICATION_FORM_URLENCODED) then begin @@ -936,7 +956,7 @@ begin lBody := lBody + lName + '=' + lValue; end; end; - AddBody(lBody, fInternalContentType); + AddBody(lBody, fContentType); aBodyStream := fRawBody; end else @@ -959,11 +979,11 @@ begin DoApplyPathParams(lURL); DoApplyQueryParams(lURL); DoEncodeURL(lURL); - DoApplyHeaders; DoApplyCookies(lURL); lBodyStream := nil; DoPrepareBodyRequest(lBodyStream); + DoApplyHeaders; case aMethod of httpGET: @@ -1281,18 +1301,18 @@ end; procedure TMVCRESTClient.SetContentType(const aContentType: string); begin - fInternalContentType := aContentType; - AddHeader(sContentType, aContentType); + fContentType := aContentType; end; function TMVCRESTClient.UserAgent(const aUserAgent: string): IMVCRESTClient; begin - Result := AddHeader(sUserAgent, aUserAgent); + Result := Self; + fUserAgent := aUserAgent; end; function TMVCRESTClient.UserAgent: string; begin - Result := HeaderValue(sUserAgent); + Result := fUserAgent; end; { TMVCRESTResponse } diff --git a/unittests/general/Several/LiveServerTestU.pas b/unittests/general/Several/LiveServerTestU.pas index 025aec4d..5842735d 100644 --- a/unittests/general/Several/LiveServerTestU.pas +++ b/unittests/general/Several/LiveServerTestU.pas @@ -677,7 +677,6 @@ begin lRes := RESTClient.Accept('text/html').Post('/system/users/logged', TSystemJSON.JSONValueToString(lJSON, false)); SplitContentMediaTypeAndCharset(lRes.ContentType, lContentType, lContentCharset); Assert.AreEqual(lContentType, TMVCMediaType.APPLICATION_JSON); - Assert.AreEqual(lContentCharset, TMVCCharSet.UTF_8); Assert.areEqual(HTTP_STATUS.OK, lRes.StatusCode); Assert.areEqual('/system/users/logged', lRes.HeaderValue('X-LOGOUT-URL')); Assert.areEqual('DELETE', lRes.HeaderValue('X-LOGOUT-METHOD')); @@ -705,7 +704,7 @@ begin lJSON := System.JSON.TJSONObject.Create; try // no request body - lRes := RESTClient.Post('/system/users/logged'); + lRes := RESTClient.AddBody('',TMVCMediaType.APPLICATION_JSON).Post('/system/users/logged'); Assert.areEqual(HTTP_STATUS.BadRequest, lRes.StatusCode, 'Empty request body doesn''t return HTTP 400 Bad Request'); @@ -779,9 +778,6 @@ var lRes: IMVCRESTResponse; lJSON: System.JSON.TJSONObject; lLogoutUrl: string; - lValue: string; - I: Integer; - lPieces: TArray; lPass: Boolean; lCookie: TCookie; begin @@ -1049,13 +1045,13 @@ begin lRes := RESTClient.Accept(TMVCMediaType.TEXT_HTML).Get('/static.html'); Assert.areEqual(404, lRes.StatusCode, '/static.html'); - lRes := RESTClient.Accept(TMVCMediaType.TEXT_HTML).Get('/static'); + lRes := RESTClient.HandleRedirects(False).Accept(TMVCMediaType.TEXT_HTML).Get('/static'); Assert.areEqual(301, lRes.StatusCode, '/static'); lRes := RESTClient.Accept(TMVCMediaType.TEXT_HTML).Get('/static/'); Assert.areEqual(200, lRes.StatusCode, '/static/'); - lRes := RESTClient.Accept(TMVCMediaType.TEXT_HTML).Get('/static/folder1'); + lRes := RESTClient.HandleRedirects(False).Accept(TMVCMediaType.TEXT_HTML).Get('/static/folder1'); Assert.areEqual(301, lRes.StatusCode, '/static/folder1'); lRes := RESTClient.Accept(TMVCMediaType.TEXT_HTML).Get('/static/folder1/'); @@ -1622,7 +1618,7 @@ begin lRes := RESTClient.Accept(TMVCMediaType.TEXT_HTML).Get('/static/'); Assert.areEqual(200, lRes.StatusCode, '/static/'); - lRes := RESTClient.Accept(TMVCMediaType.TEXT_HTML).Get('/static'); + lRes := RESTClient.HandleRedirects(False).Accept(TMVCMediaType.TEXT_HTML).Get('/static'); Assert.areEqual(301, lRes.StatusCode, '/static'); Assert.areEqual('/static/', lRes.HeaderValue('Location'), 'Wrong redirect'); end; @@ -1826,7 +1822,7 @@ begin lUrl := '..\' + lUrl; lRes := RESTClient.Accept(TMVCMediaType.TEXT_HTML).Get('/spa/' + lUrl); Assert.areEqual(404, lRes.StatusCode); - Assert.Contains(lRes.Content, '404: [EMVCException] Not Found', true); + Assert.Contains(lRes.StatusText, '[EMVCException] Not Found', True); end; end;