- Saved searches
- Use saved searches to filter your results more quickly
- License
- lenzelot79/spring-boot-jsonrpc
- Name already in use
- Sign In Required
- Launching GitHub Desktop
- Launching GitHub Desktop
- Launching Xcode
- Launching Visual Studio Code
- Latest commit
- Git stats
- Files
- README.md
- В эпоху REST мертвый вызов удаленной процедуры Java?
- JSON-RPC
- Использование JSON-RPC с Java
Saved searches
Use saved searches to filter your results more quickly
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session.
JSON-RPC library for spring-boot
License
lenzelot79/spring-boot-jsonrpc
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Sign In Required
Please sign in to use Codespaces.
Launching GitHub Desktop
If nothing happens, download GitHub Desktop and try again.
Launching GitHub Desktop
If nothing happens, download GitHub Desktop and try again.
Launching Xcode
If nothing happens, download Xcode and try again.
Launching Visual Studio Code
Your codespace will open once ready.
There was a problem preparing your codespace, please try again.
Latest commit
Git stats
Files
Failed to load latest commit information.
README.md
JSON RPC for Spring Boot 2
In modern web-applications and microservice architectures a RESTfull API is one of the most popular technique to communicate between different services. RESTfull APIs are resource-oriented. That means, a simple remote-procedure-call (RPC) cannot be designed in a convenient way. For that JSON-RPC has been introduced as protocol based on REST and JSON (https://www.jsonrpc.org/). Still I miss a simple to use integration for Spring Boot. spring-boot-jsonrpc is a library to accomplish this.
- Simple annotation-based integration in spring-boot controllers
- Simple client implementation via prototyping (like feign)
- Annotation based headers
- Works with spring-security and other method or controller based annotations
Implemented for spring-boot-starter-parent:2.x.x
Version 1.0.0-RELEASE
dependency> groupId>de.wigenso.springbootgroupId> artifactId>lenzelot-jsonrpcartifactId> version>1.0.0-RELEASEversion> dependency>
compile group: 'de.wigenso.springboot', name: 'lenzelot-jsonrpc', version: '1.0.0-RELEASE'
Creating a JSON RPC Controller
Basic example how to create a JSON RPC endpoint inside a Spring-Boot contoller:
@RequestMapping(value = "/jsonrpc/api") // (2) @RestController public class MyJsonRpcController extends JsonRpcController < // (1) @RemoteProcedure // (3) public void voidParamAndVoidReturn() < >@RemoteProcedure public String voidParamAndStringReturn() < return "Hello World"; > @RemoteProcedure // (4) public void throwsRuntimeExceptions() < throw new RuntimeException("Hello Error"); > @RemoteProcedure public String twoParamsAndStringReturn(final String str1, final int int1) < return str1 + " " + int1; > @RemoteProcedure public TestParam complexParamAndReturn(final TestParam testParam) < final TestParam r = new TestParam(); r.setStr1(testParam.getStr1() + "+"); r.setInt1(testParam.getInt1() + 1); return r; > >
To allow controllers to publish a procedure for JSON RPC extend JsonRpcController from your controller (1). The API endpoint can be defined using the @RequestMapping annotation in the spring way (2). A procedure that should
be callable via JSON RPC must be tagged with @RemoteProcedure (3). As shown in the example simple and complex types can be used in parameters. Complex types must be serializable via JSON.
One method in the previous example (4) throws an exception. If you wand to return a JSON RPC error you can implement a mapping for any exception using @ControllerAdvice implementing JsonExceptionConverter
@ControllerAdvice public class DefaultJsonExceptionConverter implements JsonExceptionConverter < @ExceptionHandler(RuntimeException.class) public JsonNode convertRuntimeException(RuntimeException e) < return messageToJsonNode(e); > @ExceptionHandler(AccessDeniedException.class) public JsonNode convertAccessDeniedException(AccessDeniedException e) < return messageToJsonNode(e); > >
The JsonExceptionConverter contains simple method to convert exception to a JsonNode. Feel free to implement custom converters. The resulting JsonNode is serialized into the error field in the JsonRpcResponse object.
Using Spring interceptor methods
JSON-RPC for spring-boot is designed in a way that you are allowed to use any spring interceptor annotation:
Example for authorization with spring security
@RemoteProcedure @PreAuthorize("hasRole('ADMIN')") public String onlyForAdmin() < return "Hello Admin!"; >
Other interceptor annotations, eg. for transaction are also supported.
If you need to implement a controller containing JSON-RPC and other endpoint together, you can define the JSON-RPC endpoint manually inside the controller.
@PostMapping("/rpc") @ResponseBody public JsonRpcResponse rpcEndpoint(@RequestBody JsonRpcRequest request) throws Throwable < return JsonRpcHandler.jsonRpcCall(request, this); // (1) >
The example defines a JSON-PRC endpoint on ‘/rpc’. The static in (1) will handle JSON-RPC calls. The second parameter to the static call must be the class containing the target procedure(s) annotated with @RemoteProcedure
Parameters of the following types will be injected by the framework (as in spring-boot) when they are added to the remote-procedures signature:
In the following example the Principal will be injected by the framework, this parameter need not to be added to the JsonRpcRequest :
@RemoteProcedure public String helloPrincipal(String say, String mark, Principal principal) < return say + " " + principal.getName() + mark; >
To handle JSON-RPC calls in Java the @JsonRpcClient can be used to define a proxy.
A client for the above example will look like this:
@JsonRpcClient("/jsonrpc/api") public interface MyJsonRpcControllerClient < void voidParamAndVoidReturn(); String voidParamAndStringReturn(); void throwsRuntimeExceptions(); String twoParamsAndStringReturn(final String str1, final int int1); TestParam complexParamAndReturn(final TestParam testParam); >
Header injection
If you need to inject parameters via a http-header and not as JSON-RPC parameter, it can be annotated with @RequestHeader from spring web:
String helloHeader(@RequestHeader("x-test") final String value);
In this example the parameter value will not be added to JSON-RPC parameters, it will be send as http-header with key «x-test».
Registration and instantiation of the Client
To get an instance of the client a bean as follows must be registered. For test the instance can be created directly in the test class.
MyJsonRpcControllerClient client() < return JsonRpcClientBuilder.of(MyJsonRpcControllerClient.class) // (1) .withRestTemplate(restTemplate) // (2) .withBaseUrl("http://localhost:" + port) // (3) .withErrorHandler(new MyJsonRpcClientErrorHandler()) // (4) .withInterceptor(retryInterceptor) // (5) .build(); >
- (1) In this example an instance of MyJsonRpcControllerClient is generated by te the framework.
- (2) optional If it is missing the library uses the default RestTemplate from spring. Use your own RestTemplate if you need to inject some headers like Authorization, or if you need a special RestTemplate like KeycloakRestTemplate if you are working with Keycloak.
- (3) The base URL of your service must be defined as shown.
- (4) optional Custom error handler
- (5) optional Interceptor that will be called before sending request to server
Error handling
For REST errors (HTTP Status 4xx, 5xx) the spring exception knwon form RestTemplate were thrown. A JSON-RPC error (HTTP Status 200, with filled error field in response body) will be transformed into a JsonRpcClientException . If you need a custom error handler you implement an own error handler and register it explained above in (4).
Example for a custom error handler:
public class MyJsonRpcClientErrorHandler implements JsonRpcClientErrorHandler < @Override public void handleError(JsonNode errorNode) < throw new MyJsonRpcClientException(errorNode); > >
Retry policy
The client library has no own retry policy implemented. But using an interceptor as shown in example above in step (5), a retry policy can implemented very easy using spring-retry.
Following steps are required for that:
(1) Include spring retry and aop:
dependency> groupId>org.springframework.retrygroupId> artifactId>spring-retryartifactId> dependency> dependency> groupId>org.springframework.bootgroupId> artifactId>spring-boot-starter-aopartifactId> dependency>
(2) Annotate a spring configuration with @EnableRetry
(3) Implement your own retry interceptor like this:
@Service public class JsonRpcClientRetryInterceptor implements JsonRpcClientInterceptor < @Retryable(value = ExceptionYouWantARetryFor.class, maxAttempts = 4) public ResponseEntityJsonRpcResponse> execute(final HttpEntityJsonRpcRequest> entity, final JsonRpcClientTarget target) < return target.execute(entity); > >
(4) Register it in MyJsonRpcControllerClient client() using withInterceptor(retryInterceptor) (example above)
For advanced testing there is a test project on GitHub, containing all the examples above: spring-boot-jsonrpc-test
В эпоху REST мертвый вызов удаленной процедуры Java?
Когда вы пишете веб-сервисы в наше время, вы можете быть уверены, что REST будет вашим первым выбором и, вероятно, вашим единственным выбором. Иногда вам просто нужно быстро создать что-то похожее на RPC, которое может быть вызвано простым HTTP-вызовом и использует JSON, как все классные ребята в блоке. Введите JSON-RPC .
JSON-RPC
RPC действительно получил дурную славу благодаря некоторым стандартам, которые использовались для его достижения. Большинство разработчиков вздрагивают, сталкиваясь с WSDL и конвертами SOAP. Тем не менее, RPC по-прежнему имеет много вариантов использования, например, для удаленного взаимодействия между бизнес-интерфейсом и выделенным фоном. Большинство пользователей Spring знакомы с функциями удаленного взаимодействия, которые он предоставляет, включая HTTP-вызов (с использованием сериализации Java), JMS и простой старый RMI. JSON-RPC может быть очень хорошей заменой в таких условиях и обеспечивает простой способ тестирования и вызова вашего API с использованием только браузера.
JSON-RPC является официальным стандартом, теперь в версии 2.0. Он использует полезную нагрузку JSON для определения как запроса, так и ответа на вызов RPC. Стандартный вызов JSON-RPC выглядит следующим образом:
"id":1234, "method":"myRpcMethod", "params":["test"] >
С помощью JSON-RPC вы можете выбрать выделенную конечную точку для каждой службы или одну конечную точку, различая службы на уровне сервера, добавив префикс имени метода к идентификатору службы.
Ответ будет либо результатом вызова, либо структурой, возвращающей информацию об ошибке в случае сбоя вызова.
Использование JSON-RPC с Java
Существует несколько библиотек JSON-RPC. Однако, как я выяснил, на самом деле стоит обратить внимание только на одно, особенно если вы используете Spring: jsonrpc4j . Он использует Jackson для обеспечения отображения между POJO и JSON и поэтому может быть легко расширен для поддержки множества библиотек Java, таких как поддержка сериализации для Joda Time и новый Money API.
С jsonrpc4j представить сервис как сервис JSON очень просто. Я собираюсь дать вам базовую настройку для предоставления сервиса в Spring Boot, но вы можете найти больше информации в документации проекта.
Например, скажем, у нас есть сервис, который должен быть представлен следующим образом:
public interface MyService String sayHelloWorld(String name); > public class MyServiceImpl implements MyService public String sayHelloWorld(String name) return "Hello world, " + name; > >
Чтобы предоставить этот сервис JSON-RPC с Spring Boot, вам нужен следующий конфигурационный файл с jsonrpc4j:
@SpringBootApplication public class RpcApplication @Bean public MyService myService() @Bean(name = "/rpc/myservice") public JsonServiceExporter jsonServiceExporter() >
Вот и все. Запустите приложение Boot и выполните следующую curl команду:
curl -v -X POST -d '' http://localhost:8080/rpc/myservice
Вы должны получить следующий ответ:
И это все для демонстрации методов JSON-RPC с помощью Spring Boot. Очень просто, очень быстро и очень мощно. Лично мне очень нравятся API-интерфейсы JSON-RPC для внутреннего использования, потому что у него такая маленькая кривая обучения. Хотя это определенно не REST, он позволяет быстро предоставлять сервис через интерфейс HTTP с структурами данных JSON. API-интерфейсы JSON-RPC могут быть отличным дополнением к вашим API-интерфейсам REST. Нет сомнений в том, что API-интерфейсы REST предпочтительнее для внешних веб-сервисов, но для внутренней связи или внутренних API-интерфейсов JSON-RPC может обеспечить быструю альтернативу экстернализации сервисов, не беспокоясь о том, чтобы сопоставить все с ресурсами RESTful.