EMS ペット リソースの作成
チュートリアル:EMS クライアントを使用してカスタム EMS リソースにアクセスする への移動
目次
このチュートリアルでは、まず、使用可能なメソッドをすべて公開する EMS リソース(詳細は「EMS リソースの概要」を参照)を新規作成し、実装します。
このチュートリアルの EMS ペット リソースは、ペットについての情報(名前や種類など)を EMS サーバー内のファイルに格納します。EMS ペット リソースでは使用可能なエンドポイントが実装されており、EMS ペット クライアント アプリケーションからその EMS ペット リソース エンドポイントを呼び出すことで、ペットのリストを取得したり格納されたペットの情報を変更することができます。
EMS ペット リソースの作成
EMS リソースを新規作成し、公開する EMS リソース エンドポイントを定義する必要があります。詳細は、「EMS リソースの概要」を参照してください。
- RAD Studio で[EMS パッケージ ウィザード]を開きます。
- Delphi の場合: [ファイル|新規作成|その他...|Delphi プロジェクト|EMS|EMS パッケージ]
- [リソースを含むパッケージを作成する]を選択します。
- EMS リソース名とファイルの種類を指定します。
- [リソース名]: Pets
- [ファイルの種類]: [ユニット]
- EMS リソースで公開する EMS エンドポイントを選択します。このチュートリアルでは、すべてのエンドポイントを選択します。
- [完了]ボタンをクリックします。
- [プロジェクト マネージャ]で、ユニットの名前を「PetsResource」に変更します。
- プロジェクトを保存します。
作成された 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 クライアント アプリケーションでこのデータ ユニットを使って、データをシリアル化する必要があります。
アプリケーションで使用するペット型のユニットを新規作成します。手順は以下のとおりです。
- [プロジェクト マネージャ]でプロジェクトを右クリックし、[新規追加|ユニット]を選択します。
- ユニットの名前を「PetType」に変更します。
- 次に示す 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;
- ユニットに以下のコードを追加します。
- Delphi の場合:
constructor TPet.Create(const AId: integer; const AName, AKind: string); begin FName := AName; FKind := AKind; FId := AId; end;
- ペット オブジェクトをシリアル化するために、ユニット内に 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;
- 以下の uses 句を追加します。
- Delphi の場合:
uses System.JSON, System.Generics.Collections;
-
ユニットのメソッドを実装します。
- 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 です。
- [プロジェクト マネージャ]でプロジェクトを右クリックし、[新規追加|ユニット]を選択します。
- ユニットの名前を「PetsManager」に変更します。
- 次に示す 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;
- 以下の uses 句を追加します。
- Delphi の場合:
uses System.SysUtils, System.IniFiles, System.Generics.Collections, PetType, System.Classes, System.StrUtils, System.Types;
- ユニットに以下のコードを追加します。
- 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 エンドポイント メソッドの実装を追加する必要があります。
- 以下の uses 句を追加します。
- Delphi の場合:
uses PetType, PetsManager;
- EMS リソース内に以下の private 変数を作成します。
- Delphi の場合:
private FPetsManager: TPetsManager;
-
ユニットに以下のコードを追加します。
- 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 クライアント アプリケーションに公開します。
- システムに EMS サーバーがセットアップされていることを確認します。
- 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}}