Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork6
JSON RPC Framework on Delphi
License
chuacw/JSONRPC_Framework
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
- Introduction
- Creating an interface
- Obtaining an ISomeJSONRPC interface
- Client or Server?
- Making JSON RPC calls in the client
- JSON RPC server
- Handling Exceptions
- Events
- Logging
- JSON RPC transport wrappers
- Using the HTTP transport wrapper
- Using the TCP transport wrapper
- Handling large numbers
- Troubleshooting
- Extensibility
- Examples
- Bugs / Feature Requests
- Discussions
- Licensing
- Further development
This is a JSON RPC Framework for Delphi, implementing both the code for theclient and the server side, by Chee-Wee Chua.
On the client side, it is easy to use, and allows you to just design aninterface, obtain the interface from a function you designed (an expert/wizardmay appear in future), and call it.
The JSON RPC can run over HTTP(S), or TCP, or whatever extensible protocol theremay be, as long as you create a class that descends from TJSONRPCTransportWrapper.
You create an interface that mirrors what the server offers.In the rest of this document, we'll refer to the example of an interface called ISomeJSONRPC.
ISomeJSONRPC = interface(IJSONRPCMethods) [YourGUIDhere] // it is important to declare a GUID, or the compiler will complain "E2015 Operator not applicable to this operand type" [JSONRPCNotify] procedure ANotifyMethod; function AddSomeXY(X, Y: Integer): Integer; procedure SomeSafeCallException; safecall;end;No matter what your design is, your interface needs to descend from IJSONRPCMethods.
You'll also need to register the interface by calling InvRegistry.RegisterInterfaceon your interface, like so:
InvRegistry.RegisterInterface(ISomeJSONRPC)
It is recommended that you call RegisterInterface in the initialization, sothat if you implement the server at the same time, the interface is registeredon the server side as well.
The passing of most parameters are supported with the exception of the following:
open arrays,
array of const
array of X, instead, specify the parameter type as TArray
array of const, instead, specify the parameter type as TArray
Create a function that returns an ISomeJSONRPC interface. This will alwaysbe the type of TJSONRPCWrapper, which you'll cast to ISomeJSONRPC.
The most simple function to return an ISomeJSONRPC interface is as follows:
function GetSomeJSONRPC(const ServerURL: string): ISomeJSONRPC;begin RegisterJSONRPCWrapper(TypeInfo(ISomeJSONRPC)); var LJSONRPCWrapper := TJSONRPCWrapper.Create(nil); LJSONRPCWrapper.ServerURL := ServerURL; // declare a GUID on your interface, or the compiler will complain "E2015 Operator not applicable to this operand type" on the line below. Result := LJSONRPCWrapper as ISomeJSONRPC;end;You can choose to only implement the client, while the server is implemented bysome other entity.
Alternatively, you can choose to implement only the server, handling calls from clients.
You can also implement both the client and the server if you so desire.
JSON RPC calls are dispatched to the server when you make any calls to avariable of the type ISomeJSONRPC.
When you call ANotifyMethod, it's executed on the server, and doesn't returnany results, since it's a procedure.
When you call AddSomeXY, specifying X and Y, it returns an integer aftergetting executed on the server side.
If your return result is based on the TJSONValue type, then it is automatically freed.If it is a native type such as a record or a string (classes not supported),then it is automatically managed by the Delphi RTL.
Create the server by descending it from the TInvokableClass, and include yourinterface with it.
TSomeJSONRPC = class(TInvokableClass, ISomeJSONRPC) public constructor Create; override; destructor Destroy; override; { ISomeJSONRPC } procedure ANotifyMethod; function AddSomeXY(X: Integer; Y: Integer): Integer; procedure SomeSafeCallException; safecall; end;You need to register the server class you've implemented by calling
- InvRegistry.RegisterInvokableClass(TSomeJSONRPC);
- RegisterJSONRPCWrapper(TypeInfo(ISomeJSONRPC));
Notification IDs are automatically returned, if youdo not include the[JSONNotify] attribute on your method.
When you call, for example, SomeSafeCallException, a method that may or may notthrow an exception during its execution, if you choose a central exceptionhandler, mark it with a safecall directive.
If you choose not to have a central exception handler, you need to wrap eachJSON RPC call with a try except handler.
To set up a central exception handler, use the AssignJSONRPCSafeCallExceptionHandler routine.
Each stage of the JSON RPC process is marked with events.
The JSON RPC wrapper has 3 events that you can assign your own routines to, inorder to monitor outgoing client requests, incoming server responses, and theURL that requests are sent to (only if the final URL is different from the base URL).
- OnLogOutgoingJSONRequest
- reference to procedure(const AJSONRPCRequest: string)
- OnLogIncomingJSONResponse
- reference to procedure(const AJSONRPCResponse: string);
- OnLogServerURL
- reference to procedure(const AServerURL: string);
The JSON RPC server wrapper has 2 events that you can also assign your ownroutines to, in order to monitor incoming client requests, and outgoing server responses.
- OnLogIncomingJSONRequest
- reference to procedure(const AJSONRPCRequest: string);
- OnLogOutgoingJSONResponse
- reference to procedure(const AJSONRPCResponse: string);
The JSON RPC framework supports logging outgoing request and incoming responseon the client side, as well as logging incoming request and outgoing response on the server side.
To enable client side logging, assign handlers to OnLogOutgoingJSONRequest andOnLogIncomingJSONResponse properties.
The handlers have the signature: procedure(const JSON: string);
var LJSONRPCWrapper := TJSONRPCWrapper.Create(nil); ... LJSONRPCWrapper.OnLogOutgoingJSONRequest := AOnLoggingOutgoingJSONRequest; LJSONRPCWrapper.OnLogIncomingJSONResponse := AOnLoggingIncomingJSONResponse;To enable server side logging, assign handlers to OnLogIncomingJSONRequest andOnLogOutgoingJSONResponse properties.
The handlers have the signature: procedure(const JSON: string);
var LServer: TJSONRPCServerRunner;...begin LServer := TJSONRPCServerIdHTTPRunner.Create; // Match the runner type with the client's ... LServer.OnLogIncomingJSONRequest := procedure (const AJSONRequest: string) begin WriteLn('Received JSON RPC: ', AJSONRequest); end; LServer.OnLogOutgoingJSONResponse := procedure (const AJSONResponse: string) begin WriteLn('Sent JSON RPC: ', AJSONResponse); end;There are 2 existing transport wrappers, and they are located inJSONRPC.TransportWrapper.HTTP.pas and JSONRPC.TransportWrapper.TCP.pas.
Having a transport wrapper isolates the JSON RPC framework from dealing directlywith any transport protocol related code.
Design your transport wrapper class in a unit, and then in your initializationcode, assign your class to the global variableGJSONRPCTransportWrapperClass.
The transport wrapper needs to be used in both the client and the server.
In order to use the HTTP transport wrapper, include the unitJSONRPC.TransportWrapper.HTTP in your code.
In order to use the TCP transport wrapper, include the unitJSONRPC.TransportWrapper.TCP in your code.
Delphi doesn't handle serializing large numbers well, as certain routines donot transform numbers precise enough, ie, StrToFloat and FloatToStr routines, among others.
In addition, because the range of the MinValue and MaxValue definitions infloating point numbers are not compatible between 32-bit and 64-bit Delphi,handling floating point numbers are problematic.
As such, this JSON RPC framework handles large numbers by using Rudy Velthuis'BigNumbers framework. You can either get it from GitHub's TurboPack repository,or use RAD Studio's GetIt.
It is recommended that you choose to use BigDecimals and BigIntegers whenserializing numbers.
However, if you do not wish to follow the recommendations, you can still useany of the native Delphi floating number types: Single, Double, Extended.
When implementing your JSON RPC interface, besides inheriting from IJSONRPCMethods,you'll need to add a GUID to your interface, failure to do so will get you thecompile-time error "E2015 Operator not applicable to this operand type".
When implementing the server, you'll need to call RegisterInvokableClass on yourserver class.
What if you want to handle custom data types on the server?
You can design a custom record data type, and then register it usingRegisterRecordHandler, without altering any part of the framework.
Examples directory was accidentally destroyed. Working on restoration.
If you find any bugs, pleasefile an issue on therepository.
For discussions of any new features, please visitJSON RPC Framework discussions.
Commercial use prohibited.
Further development of this library has moved elsewhere.
About
JSON RPC Framework on Delphi
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Releases
Sponsor this project
Uh oh!
There was an error while loading.Please reload this page.