mirror of
https://github.com/danieleteti/delphimvcframework.git
synced 2024-11-15 07:45:54 +01:00
Added
function OKResponse(const Body: TObject): IMVCResponse; overload; function OKResponse: IMVCResponse; overload; function NotFoundResponse(const Body: TObject): IMVCResponse; overload; function NotFoundResponse: IMVCResponse; overload; function NoContentResponse: IMVCResponse; function UnauthorizedResponse: IMVCResponse; function BadRequestResponse: IMVCResponse; overload; function BadRequestResponse(const Error: TObject): IMVCResponse; overload; function CreatedResponse(const Location: string = ''; const Body: TObject = nil): IMVCResponse; function AcceptedResponse(const Location: string = ''; const Body: TObject = nil): IMVCResponse; function ConflictResult: IMVCResponse; function InternalServerErrorResponse: IMVCResponse;
This commit is contained in:
parent
8c80ed7a3e
commit
af0984e050
Binary file not shown.
@ -8,7 +8,7 @@ uses
|
||||
FireDAC.Stan.Param, FireDAC.Stan.Error, FireDAC.DatS, FireDAC.Phys.Intf,
|
||||
FireDAC.DApt.Intf, Data.DB, FireDAC.Comp.DataSet, FireDAC.Comp.Client,
|
||||
Vcl.Grids, Vcl.DBGrids, Vcl.ExtCtrls, Vcl.StdCtrls, MVCFramework.RESTClient.Intf, MVCFramework.RESTClient,
|
||||
Vcl.DBCtrls, MVCFramework.DataSet.Utils;
|
||||
Vcl.DBCtrls, MVCFramework.DataSet.Utils, Vcl.Buttons;
|
||||
|
||||
type
|
||||
TMainForm = class(TForm)
|
||||
@ -38,11 +38,8 @@ type
|
||||
procedure btnFilterClick(Sender: TObject);
|
||||
private
|
||||
fFilter: string;
|
||||
fLoading: Boolean;
|
||||
fRESTClient: IMVCRESTClient;
|
||||
fAPIBinder: TMVCAPIBinder;
|
||||
{ Private declarations }
|
||||
procedure ShowError(const AResponse: IMVCRESTResponse);
|
||||
procedure SetFilter(const Value: string);
|
||||
public
|
||||
property Filter: string read fFilter write SetFilter;
|
||||
@ -102,18 +99,4 @@ begin
|
||||
EditFilter.Text := Value;
|
||||
end;
|
||||
|
||||
procedure TMainForm.ShowError(const AResponse: IMVCRESTResponse);
|
||||
begin
|
||||
if not AResponse.Success then
|
||||
MessageDlg(
|
||||
AResponse.StatusCode.ToString + ': ' + AResponse.StatusText + sLineBreak +
|
||||
'[' + AResponse.Content + ']',
|
||||
mtError, [mbOK], 0)
|
||||
else
|
||||
MessageDlg(
|
||||
AResponse.StatusCode.ToString + ': ' + AResponse.StatusText + sLineBreak +
|
||||
AResponse.Content,
|
||||
mtError, [mbOK], 0);
|
||||
end;
|
||||
|
||||
end.
|
||||
|
@ -82,6 +82,11 @@ type
|
||||
function GetMVCResponseWithObjectDictionary: IMVCResponse;
|
||||
[MVCPath('/mvcresponse/message/builder/headers')]
|
||||
function GetMVCResponseSimpleBuilderWithHeaders: IMVCResponse;
|
||||
[MVCPath('/mvcresponse/message/builder/nobody')]
|
||||
function GetMVCResponseNoBody: IMVCResponse;
|
||||
// Standard Responses
|
||||
[MVCPath('/mvcresponse/ok')]
|
||||
function GetOKResponse: IMVCResponse;
|
||||
end;
|
||||
|
||||
implementation
|
||||
@ -132,6 +137,15 @@ end;
|
||||
|
||||
|
||||
|
||||
function TMyController.GetMVCResponseNoBody: IMVCResponse;
|
||||
begin
|
||||
Result := MVCResponseBuilder
|
||||
.StatusCode(HTTP_STATUS.OK)
|
||||
.Header('header1', 'Hello World')
|
||||
.Header('header2', 'foo bar')
|
||||
.Build;
|
||||
end;
|
||||
|
||||
function TMyController.GetMVCResponseSimple: IMVCResponse;
|
||||
begin
|
||||
Result := MVCResponseBuilder
|
||||
@ -152,10 +166,7 @@ end;
|
||||
|
||||
function TMyController.GetMVCResponseWithData: IMVCResponse;
|
||||
begin
|
||||
Result := MVCResponseBuilder
|
||||
.StatusCode(HTTP_STATUS.OK)
|
||||
.Body(TPerson.Create('Daniele','Teti', 99))
|
||||
.Build;
|
||||
Result := OKResponse(TPerson.Create('Daniele','Teti', 99));
|
||||
end;
|
||||
|
||||
function TMyController.GetMVCResponseWithDataAndMessage: IMVCResponse;
|
||||
@ -191,22 +202,21 @@ end;
|
||||
|
||||
function TMyController.GetMVCResponseWithObjectList: IMVCResponse;
|
||||
begin
|
||||
Result := MVCResponseBuilder
|
||||
.StatusCode(HTTP_STATUS.OK)
|
||||
.Body(TObjectList<TPerson>.Create([
|
||||
TPerson.Create('Daniele','Teti', 99),
|
||||
TPerson.Create('Peter','Parker', 25),
|
||||
TPerson.Create('Bruce','Banner', 45)
|
||||
])
|
||||
).Build;
|
||||
Result := OKResponse(TObjectList<TPerson>.Create([
|
||||
TPerson.Create('Daniele','Teti', 99),
|
||||
TPerson.Create('Peter','Parker', 25),
|
||||
TPerson.Create('Bruce','Banner', 45)
|
||||
]));
|
||||
end;
|
||||
|
||||
function TMyController.GetOKResponse: IMVCResponse;
|
||||
begin
|
||||
Result := OKResponse;
|
||||
end;
|
||||
|
||||
function TMyController.GetMVCResponseWithJSON: IMVCResponse;
|
||||
begin
|
||||
Result := MVCResponseBuilder
|
||||
.StatusCode(HTTP_STATUS.OK)
|
||||
.Body(StrToJSONObject('{"name":"Daniele","surname":"Teti"}'))
|
||||
.Build;
|
||||
Result := OKResponse(StrToJSONObject('{"name":"Daniele","surname":"Teti"}'));
|
||||
end;
|
||||
|
||||
function TMyController.GetSingleObject: TPerson;
|
||||
|
@ -675,12 +675,37 @@ type
|
||||
var AIsAuthorized: Boolean);
|
||||
end;
|
||||
|
||||
// std responses
|
||||
|
||||
IMVCResponse = interface
|
||||
['{9DFEC741-EE38-4AC9-9C2C-9EA0D15D08D5}']
|
||||
function GetData: TObject;
|
||||
function GetMessage: string;
|
||||
function GetStatusCode: Integer;
|
||||
function GetHeaders: TStringList;
|
||||
procedure SetData(const Value: TObject);
|
||||
procedure SetMessage(const Value: string);
|
||||
procedure SetHeaders(const Headers: TStringList);
|
||||
procedure SetObjectDictionary(const Value: IMVCObjectDictionary);
|
||||
function GetObjectDictionary: IMVCObjectDictionary;
|
||||
procedure SetStatusCode(const Value: Integer);
|
||||
function GetIgnoredList: TMVCIgnoredList;
|
||||
function HasHeaders: Boolean;
|
||||
function HasBody: Boolean;
|
||||
property StatusCode: Integer read GetStatusCode write SetStatusCode;
|
||||
property Message: string read GetMessage write SetMessage;
|
||||
property Data: TObject read GetData write SetData;
|
||||
property ObjectDictionary: IMVCObjectDictionary read GetObjectDictionary write SetObjectDictionary;
|
||||
property Headers: TStringList read GetHeaders write SetHeaders;
|
||||
end;
|
||||
|
||||
TMVCRenderer = class(TMVCBase)
|
||||
protected
|
||||
FContext: TWebContext;
|
||||
FContentCharset: string;
|
||||
FResponseStream: TStringBuilder;
|
||||
function ToMVCList(const AObject: TObject; AOwnsObject: Boolean = False): IMVCList;
|
||||
function StatusCodeResponseWithOptionalBody(const StatusCode: Word; const Body: TObject): IMVCResponse;
|
||||
public { this must be public because of entity processors }
|
||||
function GetContentType: string;
|
||||
function GetStatusCode: Integer;
|
||||
@ -690,6 +715,9 @@ type
|
||||
procedure Redirect(const AUrl: string); virtual;
|
||||
procedure ResponseStatus(const AStatusCode: Integer; const AReasonString: string = ''); virtual;
|
||||
class procedure InternalRenderMVCResponse(const Controller: TMVCRenderer; const MVCResponse: TMVCResponse);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
///
|
||||
/// <summary>
|
||||
/// HTTP Status 201 indicates that as a result of HTTP POST request, one or more new resources have been successfully created on server.
|
||||
/// The response may contain URI in Location header field in HTTP headers list, which can have reference to the newly created resource. Also, response payload also may include an entity containing a list of resource characteristics and location(s) from which the user or user agent can choose the one most appropriate.
|
||||
@ -699,7 +727,36 @@ type
|
||||
/// https://restfulapi.net/http-status-201-created/
|
||||
/// </remarks>
|
||||
procedure Render201Created(const Location: string = '';
|
||||
const Reason: string = ''); virtual;
|
||||
const Reason: string = ''); virtual; deprecated;
|
||||
|
||||
|
||||
//Response Result
|
||||
{
|
||||
BadRequestResult
|
||||
ConflictResult
|
||||
NoContentResult
|
||||
NotFoundResult
|
||||
OkResult
|
||||
UnauthorizedResult
|
||||
UnprocessableEntityResult
|
||||
UnsupportedMediaTypeResult
|
||||
ConflictResult
|
||||
InternalServerErrorResult
|
||||
}
|
||||
|
||||
function OKResponse(const Body: TObject): IMVCResponse; overload;
|
||||
function OKResponse: IMVCResponse; overload;
|
||||
function NotFoundResponse(const Body: TObject): IMVCResponse; overload;
|
||||
function NotFoundResponse: IMVCResponse; overload;
|
||||
function NoContentResponse: IMVCResponse;
|
||||
function UnauthorizedResponse: IMVCResponse;
|
||||
function BadRequestResponse: IMVCResponse; overload;
|
||||
function BadRequestResponse(const Error: TObject): IMVCResponse; overload;
|
||||
function CreatedResponse(const Location: string = ''; const Body: TObject = nil): IMVCResponse;
|
||||
function AcceptedResponse(const Location: string = ''; const Body: TObject = nil): IMVCResponse;
|
||||
function ConflictResult: IMVCResponse;
|
||||
function InternalServerErrorResponse: IMVCResponse;
|
||||
|
||||
/// <summary>
|
||||
/// Allow a server to accept a request for some other process (perhaps a batch-oriented process that is only run once per day) without requiring that the user agents connection to the server persist until the process is completed.
|
||||
/// The entity returned with this response SHOULD describe the requests current status and point to (or embed) a status monitor that can provide the user with (or without) an estimate of when the request will be fulfilled.
|
||||
@ -708,13 +765,18 @@ type
|
||||
/// https://restfulapi.net/http-status-202-accepted/
|
||||
/// </remarks>
|
||||
procedure Render202Accepted(const HREF: string; const ID: string;
|
||||
const Reason: string = 'Accepted'); virtual;
|
||||
const Reason: string = 'Accepted'); virtual; deprecated;
|
||||
/// <summary>
|
||||
/// HTTP Status 204 (No Content) indicates that the server has successfully fulfilled the request and that there is no content to send in the response payload body. The server might want to return updated meta information in the form of entity-headers, which if present SHOULD be applied to current documents active view if any.
|
||||
/// The 204 response MUST NOT include a message-body and thus is always terminated by the first empty line after the header fields.
|
||||
/// </summary>
|
||||
procedure Render204NoContent(const Location: string = '';
|
||||
const Reason: string = ''); virtual;
|
||||
const Reason: string = ''); virtual; deprecated;
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
function Serializer: IMVCSerializer; overload;
|
||||
function Serializer(const AContentType: string;
|
||||
const ARaiseExceptionIfNotExists: Boolean = True): IMVCSerializer; overload;
|
||||
@ -1091,29 +1153,6 @@ type
|
||||
end;
|
||||
|
||||
|
||||
// std responses
|
||||
|
||||
IMVCResponse = interface
|
||||
['{9DFEC741-EE38-4AC9-9C2C-9EA0D15D08D5}']
|
||||
function GetData: TObject;
|
||||
function GetMessage: string;
|
||||
function GetStatusCode: Integer;
|
||||
function GetHeaders: TStringList;
|
||||
procedure SetData(const Value: TObject);
|
||||
procedure SetMessage(const Value: string);
|
||||
procedure SetHeaders(const Headers: TStringList);
|
||||
procedure SetObjectDictionary(const Value: IMVCObjectDictionary);
|
||||
function GetObjectDictionary: IMVCObjectDictionary;
|
||||
procedure SetStatusCode(const Value: Integer);
|
||||
function GetIgnoredList: TMVCIgnoredList;
|
||||
function HasHeaders: Boolean;
|
||||
function HasBody: Boolean;
|
||||
property StatusCode: Integer read GetStatusCode write SetStatusCode;
|
||||
property Message: string read GetMessage write SetMessage;
|
||||
property Data: TObject read GetData write SetData;
|
||||
property ObjectDictionary: IMVCObjectDictionary read GetObjectDictionary write SetObjectDictionary;
|
||||
property Headers: TStringList read GetHeaders write SetHeaders;
|
||||
end;
|
||||
|
||||
TMVCBaseResponse = class abstract (TInterfacedObject, IMVCResponse)
|
||||
protected
|
||||
@ -3902,6 +3941,55 @@ begin
|
||||
'Hint: Messaging extensions require a valid clientid. Did you call /messages/clients/YOUR_CLIENT_ID ?');
|
||||
end;
|
||||
|
||||
function TMVCRenderer.BadRequestResponse: IMVCResponse;
|
||||
begin
|
||||
Result := StatusCodeResponseWithOptionalBody(HTTP_STATUS.BadRequest, nil);
|
||||
end;
|
||||
|
||||
function TMVCRenderer.AcceptedResponse(const Location: string;
|
||||
const Body: TObject): IMVCResponse;
|
||||
var
|
||||
lRespBuilder: IMVCResponseBuilder;
|
||||
begin
|
||||
lRespBuilder := MVCResponseBuilder;
|
||||
if not Location.IsEmpty then
|
||||
begin
|
||||
lRespBuilder.Header('location', Location)
|
||||
end;
|
||||
if Assigned(Body) then
|
||||
begin
|
||||
lRespBuilder.Body(Body, True);
|
||||
end;
|
||||
Result := lRespBuilder.StatusCode(HTTP_STATUS.Accepted).Build;
|
||||
end;
|
||||
|
||||
function TMVCRenderer.BadRequestResponse(const Error: TObject): IMVCResponse;
|
||||
begin
|
||||
Result := StatusCodeResponseWithOptionalBody(HTTP_STATUS.BadRequest, Error);
|
||||
end;
|
||||
|
||||
function TMVCRenderer.ConflictResult: IMVCResponse;
|
||||
begin
|
||||
Result := StatusCodeResponseWithOptionalBody(HTTP_STATUS.Conflict, nil);
|
||||
end;
|
||||
|
||||
function TMVCRenderer.CreatedResponse(const Location: string;
|
||||
const Body: TObject): IMVCResponse;
|
||||
var
|
||||
lRespBuilder: IMVCResponseBuilder;
|
||||
begin
|
||||
lRespBuilder := MVCResponseBuilder;
|
||||
if not Location.IsEmpty then
|
||||
begin
|
||||
lRespBuilder.Header('location', Location)
|
||||
end;
|
||||
if Assigned(Body) then
|
||||
begin
|
||||
lRespBuilder.Body(Body, True);
|
||||
end;
|
||||
Result := lRespBuilder.StatusCode(HTTP_STATUS.Created).Build;
|
||||
end;
|
||||
|
||||
function TMVCRenderer.GetContentType: string;
|
||||
begin
|
||||
Result := GetContext.Response.ContentType.Trim;
|
||||
@ -3990,6 +4078,36 @@ end;
|
||||
|
||||
end;
|
||||
|
||||
function TMVCRenderer.InternalServerErrorResponse: IMVCResponse;
|
||||
begin
|
||||
Result := StatusCodeResponseWithOptionalBody(HTTP_STATUS.InternalServerError, nil);
|
||||
end;
|
||||
|
||||
function TMVCRenderer.NoContentResponse: IMVCResponse;
|
||||
begin
|
||||
Result := StatusCodeResponseWithOptionalBody(HTTP_STATUS.NoContent, nil);
|
||||
end;
|
||||
|
||||
function TMVCRenderer.NotFoundResponse: IMVCResponse;
|
||||
begin
|
||||
Result := StatusCodeResponseWithOptionalBody(HTTP_STATUS.NotFound, nil);
|
||||
end;
|
||||
|
||||
function TMVCRenderer.NotFoundResponse(const Body: TObject): IMVCResponse;
|
||||
begin
|
||||
Result := StatusCodeResponseWithOptionalBody(HTTP_STATUS.NotFound, Body);
|
||||
end;
|
||||
|
||||
function TMVCRenderer.OKResponse: IMVCResponse;
|
||||
begin
|
||||
Result := StatusCodeResponseWithOptionalBody(HTTP_STATUS.OK, nil);
|
||||
end;
|
||||
|
||||
function TMVCRenderer.OKResponse(const Body: TObject): IMVCResponse;
|
||||
begin
|
||||
Result := StatusCodeResponseWithOptionalBody(HTTP_STATUS.OK, Body);
|
||||
end;
|
||||
|
||||
function TMVCController.GetViewData(const aModelName: string): TValue;
|
||||
begin
|
||||
if not FViewModel.TryGetValue(aModelName, Result) then
|
||||
@ -4274,11 +4392,28 @@ begin
|
||||
GetContext.Response.StatusCode := AValue;
|
||||
end;
|
||||
|
||||
function TMVCRenderer.StatusCodeResponseWithOptionalBody(const StatusCode: Word; const Body: TObject): IMVCResponse;
|
||||
begin
|
||||
if Body = nil then
|
||||
begin
|
||||
Result := MVCResponseBuilder.StatusCode(StatusCode).Build;
|
||||
end
|
||||
else
|
||||
begin
|
||||
Result := MVCResponseBuilder.StatusCode(StatusCode).Body(Body, True).Build;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TMVCRenderer.ToMVCList(const AObject: TObject; AOwnsObject: Boolean): IMVCList;
|
||||
begin
|
||||
Result := MVCFramework.DuckTyping.WrapAsList(AObject, AOwnsObject);
|
||||
end;
|
||||
|
||||
function TMVCRenderer.UnauthorizedResponse: IMVCResponse;
|
||||
begin
|
||||
Result := StatusCodeResponseWithOptionalBody(HTTP_STATUS.Unauthorized, nil);
|
||||
end;
|
||||
|
||||
procedure TMVCController.SetETag(const Data: String);
|
||||
begin
|
||||
Context.Response.SetCustomHeader('ETag', GetSHA1HashFromString(Data));
|
||||
|
Loading…
Reference in New Issue
Block a user