web api路由

web api路由

实现原理

web api通过资源来进行分类一个资源可以有许多action(动作),每一个action都有一个对应web api。

对于CRUD操作,资源可以是一个数据表的映射,但不必与数据表同名。

所有的资源url必须是唯一的,一个资源url对应一个web api,通过资源url就可以调用到对应的web api。

通过唯一的资源url来定位一个web api,资源url就是key(关键字),web api就是value(值),从而形成资源url-web api对字典。将所有的web api都添加进路由字典。

查路由字典的时候,通过客户端请求的资源url这个key(关键字),就能查到对应的web api。

资源url示例

https://api.example.com/v1/user/select

1.web api方法指针类型

{$IFDEF mormot2}
  THttpRequest = THttpServerRequestAbstract;
  THttpResponse = THttpServerRequestAbstract;
{$ENDIF}
{$IFDEF crosssocket}
  THttpRequest = ICrossHttpRequest;
  THttpResponse = ICrossHttpResponse;
{$ENDIF}

  TProcessRequest = procedure(const ARequest: THttpRequest;
    const AResponse: THttpResponse) of object;

2.web api路由

unit core.router;
//cxg 2025
interface

uses
  core.global, core.json,
  Generics.Collections, SysUtils;

type
  TRouter = record
    class var Dict: TDictionary<string, TProcessRequest>;  //路由字典  资源url-api对
    class procedure Route(const ARequest: THttpRequest;//字典查路由
      const AResponse: THttpResponse); static;
    class procedure Add(const APath: string;//往字典添加路由
      const OnRequest: TProcessRequest); static;
  end;

implementation

class procedure TRouter.Route(const ARequest: THttpRequest;
  const AResponse: THttpResponse);
var
  LPath: string;
  LResponseData: TJsonO;
  LSuccess: bool;
begin
  LSuccess := False;
  for LPath in TRouter.Dict.Keys do
  begin
    if LPath = TRequestFunc.Path(ARequest) then//字典查到了
    begin
      LSuccess := true;
      TRouter.Dict[LPath](ARequest, AResponse);
      Exit;
    end;
  end;
  if not LSuccess then//字典没有查到
  begin
    LResponseData := TJsonO.Create;
    LResponseData.B['success'] := False;
    LResponseData.S['message'] := 'Route fail.';
    TResponseFunc.Send(AResponse, LResponseData);
  end;
end;

class procedure TRouter.Add(const APath: string;
  const OnRequest: TProcessRequest);
begin
  if not assigned(TRouter.Dict) then
    TRouter.Dict := TDictionary<string, TProcessRequest>.Create;
  TRouter.Dict.Add(APath, OnRequest);
end;

end.

3.web api实现

type
  TFormData = record
    procedure DownloadFile(const ARequest: THttpRequest;
      const AResponse: THttpResponse);
    procedure UploadFile(const ARequest: THttpRequest;
      const AResponse: THttpResponse);

    procedure Select(const ARequest: THttpRequest;
      const AResponse: THttpResponse);
  end;

4.web api添加路由字典

var
  FormData: TFormData;
//资源url和web api一 一 对应,组成队
initialization
  TRouter.Add('/formdata/downloadfile', FormData.DownloadFile);
  TRouter.Add('/formdata/uploadfile', FormData.UploadFile);
  TRouter.Add('/formdata/select', FormData.Select);

 5.客户端请求服务演示

客户端web api定义

  TRpc = record
    //CRUD
    class function Select(const ADbid: string; ASqls: TArray<string>;
      ADataSets: TArray<TDataSet>): boolean; static;
    class function Insert(const ADbid: string; ATableNames: TArray<string>;
      ANonSaveFields: TArray<string>; ADataSets: TArray<TDataSet>;
      ACurrentRecordOnly: boolean): boolean; static;
    class function Update(const ADbid: string; ATableNames: TArray<string>;
      ANonSaveFields: TArray<string>; ADataSets: TArray<TDataSet>;
      ACurrentRecordOnly: boolean): boolean; static;
    class function Delete(const ADbid: string; ATableNames: TArray<string>;
      ADataSets: TArray<TDataSet>; ACurrentRecordOnly: boolean)
      : boolean; static;
    class function Save(const ADbid: string; ATableNames: TArray<string>;
      ANonSaveFields: TArray<string>; ADataSets: TArray<TDataSet>;
      AState: TDataSetState; ACurrentRecordOnly: boolean): boolean; static;
    class function StoredProc(ARequestData: TJsonO): TJsonO; static;
    //file transfer
    class function DownloadFile(const AFileName: string): TJsonO; static;
    class function UploadFile(const ARequestData: TJsonO): boolean; static;
  end;

 客户端请求服务

客户端请求服务的参数统一使用json格式的数据。服务端应答数据也统一使用json格式的数据。

凡一切有http client的工具开发的客户端都支持。

class function TRpc.Select(const ADbid: string; ASqls: TArray<string>;
  ADataSets: TArray<TDataSet>): boolean;
var
  LHttp: THttpClient;
  LRequestData, LResponseData: TJsonO;
  LRequestStream, LResponseStream: TStream;
  i: integer;
begin
  if ADbid = '' then
    Exit;
  LHttp := NewHttp;
  LRequestData := TJsonO.Create;
  LResponseStream := TMemoryStream.Create;
  try
    LRequestData.S['dbid'] := ADbid;//请求参数统一使用json数据
    LRequestData.i['count'] := High(ASqls) + 1;
    for i := 0 to High(ASqls) do
      LRequestData.S['sql' + i.ToString] := ASqls[i];
    LRequestStream := LRequestData.ToStream;//请求参数json数据转换为流
    LHttp.Post(url + '/webapi/select', LRequestStream, LResponseStream);//http post 发送请求
    LResponseData := SO(LResponseStream);//应答数据还原为json
    Result := LResponseData.B['success'];
    if Result then
    begin
      for i := 0 to High(ASqls) do
      begin
        ADataSets[i].JsonArrayToFields(LResponseData.A['fields' + i.ToString]);
        ADataSets[i].JsonArrayToData(LResponseData.A['data' + i.ToString]);
      end;
    end;
  finally
    LRequestStream.Free;
    LResponseStream.Free;
    LHttp.Free;
    LRequestData.Free;
    LResponseData.Free;
  end;
end;

 

posted @ 2025-09-04 08:59  delphi中间件  阅读(69)  评论(0)    收藏  举报