Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
This repository was archived by the owner on May 22, 2025. It is now read-only.

JSON RPC Framework on Delphi

License

NotificationsYou must be signed in to change notification settings

chuacw/JSONRPC_Framework

Repository files navigation

Contents

Introduction

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.

Creating an interface

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.

Passing parameters

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

Obtaining an ISomeJSONRPC interface

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;

Client or Server?

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.

Making JSON RPC calls in the client

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.

JSON RPC server

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.

Handling Exceptions

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.

Events

Each stage of the JSON RPC process is marked with events.

Client side 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);

Server side events


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);

Logging

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.

Client side logging


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;

Server side logging


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;

JSON RPC transport wrappers

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.

Using the HTTP transport wrapper


In order to use the HTTP transport wrapper, include the unitJSONRPC.TransportWrapper.HTTP in your code.

Using the TCP transport wrapper


In order to use the TCP transport wrapper, include the unitJSONRPC.TransportWrapper.TCP in your code.

Handling large numbers

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.

Troubleshooting

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.

Extensibility

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

Examples directory was accidentally destroyed. Working on restoration.

Bugs / Feature Requests

If you find any bugs, pleasefile an issue on therepository.

Discussions

For discussions of any new features, please visitJSON RPC Framework discussions.

Licensing

Commercial use prohibited.

Further development

Further development of this library has moved elsewhere.

Releases

No releases published

Sponsor this project

 

Packages

No packages published

Languages


[8]ページ先頭

©2009-2025 Movatter.jp