Creating the EMS Pets Resource
Go Up to Tutorial: Using an EMS Client to Access a Custom EMS Resource
Contents
To begin this tutorial, create a new EMS Resource that exposes all the methods available (see RAD Server Resource Overview for more information about them) and implement them.
The EMS Pets resource of this tutorial stores information about pets (such as name and kind) in a file in the RAD Server Engine (EMS Server). The EMS Pets resource implements the available endpoints and the EMS Pets client application can retrieve the list of pets or modify the stored information about them by calling these EMS Pets resource endpoints.
Creating the EMS Pets Resource
You need to create a new EMS Resource and define the EMS Resource Endpoints that are exposed. For more information, see RAD Server Resource Overview.
- Open the EMS Package Wizard in RAD Studio.
- For Delphi: File > New > Other > Delphi Projects > EMS > EMS Package.
- Select 'Create package with resource'.
- Add the EMS Resource name and file type:
- Resource name: Pets
- File Type: Unit
- Select the EMS Endpoints that the EMS Resource exposes. For this tutorial, select all endpoints.
- Click the Finish button.
- In the Projects Window, rename the unit to PetsResource.
- Save the project.
You can see the created EMS Resource in the Code tab:
- For 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;
Creating the Pet Type
You need to create a user-defined object that will be passed between the EMS Client and EMS Server Endpoints methods using JSON objects.
- Note: You need to use this data unit in the EMS Client application to serialize the data.
Create a new Pet type unit for your application, as follows:
- In the Projects Window | right-click in the project | Add New > Unit.
- Rename the unit to PetType.
- Create a new record TPet as follows:
- For 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;
- Add the following code to your unit:
- For Delphi:
constructor TPet.Create(const AId: integer; const AName, AKind: string); begin FName := AName; FKind := AKind; FId := AId; end;
- To serialize the Pet object, you need to create the the TPetJSON class in your unit. Define it as follows:
- For 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;
- Add the following uses clauses:
- For Delphi:
uses System.JSON, System.Generics.Collections;
-
Implement the methods of your unit.
- For 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;
Adding the Pets Manager
This tutorial stores the Pets data in a file in the EMS Server (pets.ini
). To access and manage the data of this file, a new unit is created in the EMS Pets Resource, called PetsManager.
- In the Projects Window | right-click in the project | Add New > Unit
- Rename the unit to PetsManager.
- Create the new TPetsManager class as follows:
- For 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;
- Add the following uses clauses:
- For Delphi:
uses System.SysUtils, System.IniFiles, System.Generics.Collections, PetType, System.Classes, System.StrUtils, System.Types;
- Add the following code to your unit:
- For 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;
Adding the Implementation to the EMS Resource Endpoints
You need to add the implementation of the EMS Endpoints methods.
- Add the following uses clauses:
- For Delphi:
uses PetType, PetsManager;
- Create the following private variable in your EMS Resource:
- For Delphi:
private FPetsManager: TPetsManager;
-
Add the following code to your unit:
- For 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;
Loading Your EMS Resource in the EMS Server
The EMS Server loads the EMS Pets Resource and exposes the EMS Pets Resource Endpoints to the EMS Client applications.
- Check that the EMS Server is set up in your system.
- To load the EMS Pets Resource, press F9 or Run > Run.
The EMS Development Server Window is now open. In the log pane you can see the EMS Pets Resource being loaded.
{"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}}