EMS ペット リソースの作成

提供: RAD Studio
移動先: 案内検索

チュートリアル:EMS クライアントを使用してカスタム EMS リソースにアクセスする への移動

このチュートリアルでは、まず、使用可能なメソッドをすべて公開する EMS リソース(詳細は「EMS リソースの概要」を参照)を新規作成し、実装します。

このチュートリアルの EMS ペット リソースは、ペットについての情報(名前や種類など)を EMS サーバー内のファイルに格納します。EMS ペット リソースでは使用可能なエンドポイントが実装されており、EMS ペット クライアント アプリケーションからその EMS ペット リソース エンドポイントを呼び出すことで、ペットのリストを取得したり格納されたペットの情報を変更することができます。

EMS ペット リソースの作成

EMS リソースを新規作成し、公開する EMS リソース エンドポイントを定義する必要があります。詳細は、「EMS リソースの概要」を参照してください。

  1. RAD Studio で[EMS パッケージ ウィザード]を開きます。
    • Delphi の場合: [ファイル|新規作成|その他...|Delphi プロジェクト|EMS|EMS パッケージ]
  2. [リソースを含むパッケージを作成する]を選択します。
    EMSPackageWizard1.png
  3. EMS リソース名とファイルの種類を指定します。
    • [リソース名]: Pets
    • [ファイルの種類]: [ユニット]
    EMSPackageWizard2.png
  4. EMS リソースで公開する EMS エンドポイントを選択します。このチュートリアルでは、すべてのエンドポイントを選択します。
    EMSPackageWizard3.png
  5. [完了]ボタンをクリックします。
  6. [プロジェクト マネージャ]で、ユニットの名前を「PetsResource」に変更します。
  7. プロジェクトを保存します。

作成された EMS リソースが[コード]タブに表示されます。

  • Delphi の場合:
  [ResourceName('Pets')]
{$METHODINFO ON}

  TPetsResource = class
  private
    FPetsManager: TPetsManager;
    function GetModuleDirectory: string;
    procedure CheckManager;
    function IdFromRequest(const ARequest: TEndpointRequest): Integer;
  public
    destructor Destroy; override;
  published
    [EndpointName('GetPets')]
    procedure Get(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse);
    [EndpointName('GetPet')]
    [ResourceSuffix('{item}')]
    procedure GetItem(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse);
    [EndpointName('AddPet')]
    procedure Post(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse);
    [EndpointName('UpdatePet')]
    [ResourceSuffix('{item}')]
    procedure PutItem(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse);
    [EndpointName('DeletePet')]
    [ResourceSuffix('{item}')]
    procedure DeleteItem(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse);
  end;
{$METHODINFO OFF}

procedure Register;

ペット型の作成

EMS クライアントと EMS サーバー エンドポイント メソッドの間で JSON オブジェクトを使って渡される、ユーザー定義オブジェクトを作成する必要があります。

メモ: EMS クライアント アプリケーションでこのデータ ユニットを使って、データをシリアル化する必要があります。

アプリケーションで使用するペット型のユニットを新規作成します。手順は以下のとおりです。

  1. [プロジェクト マネージャ]でプロジェクトを右クリックし、[新規追加|ユニット]を選択します。
  2. ユニットの名前を「PetType」に変更します。
  3. 次に示す TPet レコードを新規作成します。
    • Delphi の場合:
     TPet = record
      private
        FId: integer;
        FKind: string;
        FName: string;
      public
        constructor Create(const AId: Integer; const AName, AKind: string);
        property Name: string read FName write FName;
        property Kind: string read FKind write FKind;
        property Id: integer read FId write FId;
      end;
    
  4. ユニットに以下のコードを追加します。
    • Delphi の場合:
    constructor TPet.Create(const AId: integer; const AName, AKind: string);
    begin
      FName := AName;
      FKind := AKind;
      FId := AId;
    end;
    
  5. ペット オブジェクトをシリアル化するために、ユニット内に TPetJSON クラスを作成する必要があります。次のように定義します。
    • Delphi の場合:
     TPetJSON = class
      public
       class function JSONToPet(const AJSON: TJSONValue): TPet; static;
       class function JSONToPets(const AJSON: TJSONArray): TArray<TPet>; static;
       class procedure PetsToJSON(const APets: TArray<TPet>; const AJSON: TJSONArray); static;
       class procedure PetToJSON(const APet: TPet; const AJSON: TJSONObject); static;
      end;
    
  6. 以下の uses 句を追加します。
    • Delphi の場合:
    	uses System.JSON, System.Generics.Collections;
    
  7. ユニットのメソッドを実装します。
    • Delphi の場合:
    class function TPetJSON.JSONToPet(const AJSON: TJSONValue): TPet;
    begin
      Result := TPet.Create(AJSON.GetValue<integer>('id'),
        AJSON.GetValue<string>('kind'), AJSON.GetValue<string>('name'));
    end;
    
    class procedure TPetJSON.PetToJSON(const APet: TPet; const AJSON: TJSONObject);
    begin
      AJSON.AddPair('id', TJSONNumber.Create(APet.FId));
      AJSON.AddPair('kind', TJSONString.Create(APet.FKind));
      AJSON.AddPair('name', TJSONString.Create(APet.FName));
    end;
    
    class function TPetJSON.JSONToPets(const AJSON: TJSONArray)
      : TArray<TPet>;
    var
      LValue: TJSONValue;
      LList: TList<TPet>;
    begin
      LList := TList<TPet>.Create;
      try
        for LValue in AJSON do
          LList.Add(TPetJSON.JSONToPet(LValue));
        Result := LList.ToArray;
      finally
        LList.Free;
      end;
    end;
    
    class procedure TPetJSON.PetsToJSON(const APets: TArray<TPet>;
      const AJSON: TJSONArray);
    var
      LPet: TPet;
      LJSONObject: TJSONObject;
    begin
      for LPet in APets do
      begin
        LJSONObject := TJSONObject.Create;
        PetToJSON(LPet, LJSONObject);
        AJSON.Add(LJSONObject);
      end;
    end;
    

ペット マネージャの追加

このチュートリアルでは、ペットのデータを EMS サーバー内のファイル(pets.ini)に格納します。このファイルのデータにアクセスしたり管理するために、EMS ペット リソース内に新しいユニットを作成します。名前は PetsManager です。

  1. [プロジェクト マネージャ]でプロジェクトを右クリックし、[新規追加|ユニット]を選択します。
  2. ユニットの名前を「PetsManager」に変更します。
  3. 次に示す TPetsManager クラスを新規作成します。
    • Delphi の場合:
    type
      TPetsManager = class
        FUserID: string;
        FIniFile: TIniFile;
      private
        function EncodePet(const AName: string; const AKind: string): string;
        function DecodePetLine(const ALine: string; const AField: integer): string;
      public
        constructor Create(const ADirectory: string);
        destructor Destroy; override;
        function GetPets: TArray<TPet>;
        function GetPet(const AId: Integer; out APet: TPet): Boolean;
        procedure UpdatePet(const AId: Integer; const APet: TPet);
        procedure AddPet(const APet: TPet);
        function DeletePet(const AId: Integer): Boolean;
        function PetExists(const AId: Integer): Boolean;
      end;
    
  4. 以下の uses 句を追加します。
    • Delphi の場合:
    uses
      System.SysUtils, System.IniFiles, System.Generics.Collections, PetType,
      System.Classes, System.StrUtils, System.Types;
    
  5. ユニットに以下のコードを追加します。
    • Delphi の場合:
    constructor TPetsManager.Create(const ADirectory: string);
    var
      LPath: string;
    begin
      LPath := IncludeTrailingPathDelimiter(ExpandFileName(ADirectory)) + 'pets.ini';
      FIniFile := TIniFile.Create(LPath);
      FUserID := '0000';
    end;
    
    // Procedure to add a pet to the pets.ini file
    procedure TPetsManager.AddPet(const APet: TPet);
    begin
      FIniFile.WriteString(FUserID, APet.Id.ToString, EncodePet(APet.Name, APet.Kind));
    end;
    
    // Function to check if a pet exists in the pets.ini file
    function TPetsManager.PetExists(const AId: Integer): Boolean;
    begin
      Result := FIniFile.ValueExists(FUserID, AId.ToString);
    end;
    
    // Function to delete a pet from the pets.ini file
    function TPetsManager.DeletePet(const AId: Integer): Boolean;
    begin
      Result := PetExists(AId);
      if Result then
        FIniFile.DeleteKey(FUserID, AId.ToString);
    end;
    
    // Destructor
    destructor TPetsManager.Destroy;
    begin
      FIniFile.Free;
      inherited;
    end;
    
    // Function to get a specific pet from the pets.ini file
    function TPetsManager.GetPet(const AId: Integer; out APet: TPet): Boolean;
    var
      LName: string;
      LKind: string;
    begin
      Result := PetExists(AId);
      if Result then
      begin
        LName := DecodePetLine(FIniFile.ReadString(FUserID, AId.ToString, ''), 1);
        LKind := DecodePetLine(FIniFile.ReadString(FUserID, AId.ToString, ''), 0);
        APet := TPet.Create(AId, LName, LKind);
      end;
    end;
    
    // Function to get all pets from the pets.ini file
    function TPetsManager.GetPets: TArray<TPet>;
    var
      LList: TList<TPet>;
      LPet: TPet;
      LSection: TStrings;
      I: integer;
    begin
      LSection := nil;
      LList := nil;
      try
        LSection := TStringList.Create;
        LList := TList<TPet>.Create;
        FIniFile.ReadSectionValues(FUserID, LSection);
        for I := 0 to LSection.Count - 1 do
        begin
          LPet := TPet.Create(LSection.Names[I].ToInteger,
            DecodePetLine(LSection.ValueFromIndex[I], 1),
            DecodePetLine(LSection.ValueFromIndex[I], 0));
          LList.Add(LPet);
        end;
        Result := LList.ToArray;
      finally
        LList.Free;
        LSection.Free;
      end;
    end;
    
    // Function to update a pet from the pets.ini file
    procedure TPetsManager.UpdatePet(const AId: Integer; const APet: TPet);
    begin
      if PetExists(AId) then
        FIniFile.DeleteKey(FUserID, AId.ToString);
      FIniFile.WriteString(FUserID, AId.ToString, EncodePet(APet.Name, APet.Kind));
    end;
    
    // Function to encode the data (to be saved in the pets.ini file)
    function TPetsManager.EncodePet(const AName: string;
      const AKind: string): string;
    var
      LPet: string;
    begin
      LPet := AName + ',' + AKind;
      Result := LPet;
    end;
    // Function to decode a line from the pets.ini file
    function TPetsManager.DecodePetLine(const ALine: string;
      const AField: integer): string;
    var
      LPetField: TStringDynArray;
    begin
      LPetField := SplitString(ALine, ',');
      Result := LPetField[AField];
    end;
    

EMS リソース エンドポイントへの実装の追加

EMS エンドポイント メソッドの実装を追加する必要があります。

  1. 以下の uses 句を追加します。
    • Delphi の場合:
       uses PetType, PetsManager;
    
  2. EMS リソース内に以下の private 変数を作成します。
    • Delphi の場合:
    private
        FPetsManager: TPetsManager;
    
  3. ユニットに以下のコードを追加します。
    • Delphi の場合:
    procedure TPetsResource.Get(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse);
    var
      LPets: TArray<TPet>;
      LJSON: TJSONArray;
    begin
      LJSON := nil;
      try
        CheckManager;
        LPets := FPetsManager.GetPets;
        LJSON := TJSONArray.Create;
        TPetJSON.PetsToJSON(LPets, LJSON);
        AResponse.Body.SetValue(LJSON, True)
      except
        LJSON.Free;
        raise;
      end;
    end;
    
    
    procedure TPetsResource.GetItem(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse);
    var
      LId: Integer;
      LPet: TPet;
      LJSON: TJSONObject;
    begin
      LId := IdFromRequest(ARequest);
      CheckManager;
      if FPetsManager.GetPet(LId, LPet) then
      begin
        LJSON := TJSONObject.Create;
        try
          TPetJSON.PetToJSON(LPet, LJSON);
          AResponse.Body.SetValue(LJSON, True);
        except
          LJSON.Free;
          raise;
        end;
      end
      else
        AResponse.RaiseNotFound('', Format('Id not found: %d', [LId]));
    end;
    
    procedure TPetsResource.Post(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse);
    var
      LJSON: TJSONObject;
      LPet: TPet;
    begin
      if ARequest.Body.TryGetObject(LJSON) then
      begin
        CheckManager;
        LPet := TPetJSON.JSONToPet(LJSON);
        if FPetsManager.PetExists(LPet.Id) then
          AResponse.RaiseDuplicate('', Format('Can not add duplicate Id: %d', [LPet.Id]));
        FPetsManager.AddPet(LPet);
      end
      else
        AResponse.RaiseBadRequest('', 'JSON expected');
    end;
    
    procedure TPetsResource.PutItem(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse);
    var
      LId: Integer;
      LPet: TPet;
      LJSON: TJSONObject;
    begin
      LId := IdFromRequest(ARequest);
      if ARequest.Body.TryGetObject(LJSON) then
      begin
        CheckManager;
        LPet := TPetJSON.JSONToPet(LJSON);
        if not FPetsManager.PetExists(LId) then
          AResponse.RaiseNotFound('', Format('Can not update unknown Id: %d', [LId]));
        FPetsManager.UpdatePet(LId, LPet);
      end
      else
        AResponse.RaiseBadRequest('', 'JSON expected');
    end;
    
    procedure TPetsResource.CheckManager;
    begin
      if FPetsManager = nil then
        FPetsManager := TPetsManager.Create(GetModuleDirectory);
    end;
    
    procedure TPetsResource.DeleteItem(const AContext: TEndpointContext; const ARequest: TEndpointRequest; const AResponse: TEndpointResponse);
    var
      LId: Integer;
    begin
      LId := IdFromRequest(ARequest);
      CheckManager;
      if not FPetsManager.DeletePet(LId) then
        AResponse.RaiseNotFound('', Format('Can not delete unknown Id: %d', [LId]));
    end;
    
    destructor TPetsResource.Destroy;
    begin
      FPetsManager.Free;
      inherited;
    end;
    
    function TPetsResource.GetModuleDirectory: string;
    begin
      Result := ExtractFilePath(StringReplace(GetModuleName(HInstance), '\\?\', '', [rfReplaceAll]));
    end;
    
    function TPetsResource.IdFromRequest(const ARequest: TEndpointRequest): Integer;
    var
      LItem: string;
    begin
      LItem := ARequest.Params.Values['item'];
      if not TryStrToInt(LItem, Result) then
        EEMSHTTPError.RaiseBadRequest('', Format('Id is not an integer: "%s"', [LItem]));
    end;
    
    procedure Register;
    begin
      RegisterResource(TypeInfo(TPetsResource));
    end;
    

EMS サーバーへの EMS リソースの読み込み

EMS サーバーは、EMS ペット リソースを読み込み、EMS ペット リソース エンドポイントを EMS クライアント アプリケーションに公開します。

  1. システムに EMS サーバーがセットアップされていることを確認します。
  2. F9 を押すか[実行|実行]を選択して、EMS ペット リソースを読み込みます。

これで、[EMS 開発サーバー]ウィンドウが開きます。[ログ]ペインに、EMS ペット リソースが読み込まれる様子が表示されます。

{"Load":{"Filename":"C:\Users\Public\Documents\Embarcadero\Studio\15.0\Bpl\PetsResourcePackage.bpl","Thread":4072}}
{"RegUnit":{"Filename":"C:\Users\Public\Documents\Embarcadero\Studio\15.0\Bpl\PetsResourcePackage.bpl","Filename":"PetsResource","Thread":4072}}
{"RegResource":{"Resource":"Pets","Endpoints":["GetPets","GetPet","AddPet","UpdatePet","DeletePet"],"Thread":4072}}
EMSServerPetsResource.png

関連項目