Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better document implemented gRPC services #1449

Draft
wants to merge 6 commits into
base: 1.x-dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions client/src/main/proto/spine/client/command_service.proto
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,31 @@ package spine.client;
import "spine/options.proto";

option (type_url_prefix) = "type.spine.io";
// We put gRPC-based classes into `grpc` sub-package, which is annotated as `@Internal`
// to hide implementation details from the public API of the framework.
option java_package = "io.spine.client.grpc";
option java_multiple_files = true;
option java_outer_classname = "CommandServiceProto";

import "spine/core/command.proto";
import "spine/core/ack.proto";

// A service for sending commands from clients.
// A service for posting commands to the application backend.
//
service CommandService {

// Request to handle a command.
// Posts the given command to the application backend.
//
// When the command is successfully received by the application, it responds with
// an acknowledgement. The received `Ack` may have one of the following statuses:
//
// 1. `Ok` meaning the command is accepted for further processing.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

`OK`, meaning the ...

// 2. `Error` when a technical error occurs on the side of the application.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please be more specific. What is a technical error? What is the "side of the application"? Both client and server make the application as a whole.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

`Error`, when a ...

// 3. `Rejection` if no technical error occurred but due to the business rules the command
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

`Rejection`, if no ...

// should be immediately disqualified from being executed. A typical scenario would be
// when the permissions of a user who made a request aren't broad enough.
//
// In case of internal gRPC errors or issues on a transport layer, an `Ack` would not be
// received. All errors which occur on the side of gRCP should be handled by the means
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"gRPC"

// of the used client stub.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not "used". Maybe, "chosen", or no word at all.

//
rpc Post(core.Command) returns (core.Ack);
}
40 changes: 36 additions & 4 deletions server/src/main/java/io/spine/server/CommandService.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,13 @@
import static io.spine.server.bus.Acks.reject;

/**
* The {@code CommandService} allows client applications to post commands and
* receive updates from the application backend.
* The {@code CommandService} provides a synchronous way to post commands
* to the application backend.
*
* <p>This class is an implementation of a corresponding gRPC service. Hence, public API of this
* class is dictated by the {@linkplain CommandServiceGrpc generated code}. Despite the fact of its
* "publicity", it's not meant to be used directly. Use {@link io.spine.client.Client Client}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not true. It is meant to be used directly. Otherwise, users won't be able to assembly the definitions of services for their gRPC servers at server-side.

Please rephrase.

* to post commands to the application.
*/
public final class CommandService
extends CommandServiceGrpc.CommandServiceImplBase
Expand All @@ -55,7 +60,7 @@ public final class CommandService
private final ImmutableMap<CommandClass, BoundedContext> commandToContext;

/**
* Constructs new instance using the map from a {@code CommandClass} to
* Constructs a new instance using the map from a {@code CommandClass} to
* a {@code BoundedContext} instance which handles the command.
*/
private CommandService(Map<CommandClass, BoundedContext> map) {
Expand All @@ -70,14 +75,41 @@ public static Builder newBuilder() {
return new Builder();
}

/** Builds the service with a single Bounded Context. **/
/**
* Builds the service with a single Bounded Context.
*/
public static CommandService withSingle(BoundedContext context) {
CommandService result = newBuilder()
.add(context)
.build();
return result;
}

/**
* {@inheritDoc}
*
* <p>In the original proto definition of this service, this method is unary.
* Meaning, for every posted command only a single {@link Ack} is received in response:
*
* <pre>Ack post(Command);</pre>
*
* <p>But for every service, gRPC generates several clients: blocking, asynchronous,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are two issues with this text.

  1. It is pretty much the same for every method which is generated after gRPC. So it would be nice to write it once and "run everywhere" (meaning, reference, not copy).

  2. The wording here is a bit harsh. We aren't the authors of gRPC. And for sure we have chosen to use them voluntarily. Therefore, they don't owe us anything. But the impression of this text is that they do.

* {@link com.google.common.util.concurrent.ListenableFuture Future}-based. Each one
* has its own signature for this method. And instead of making users to implement three
* different signatures of the same method in the
* {@linkplain CommandServiceGrpc.CommandServiceImplBase server stub}, they prefer a single
* universal method that cover all the cases.
*
* <p>Although, utilizing of {@link StreamObserver} is quite controversial decision for the
* method which does not stream anything. It is still better than implementing this method
* three times. For more details on this matter, reference the issue below.
*
* <p>Please note, all the errors, occurring on the side of the application are still
* propagated through the {@linkplain Ack acknowledgement}. They are not passed into the
* {@linkplain StreamObserver#onError(Throwable) observer}.
*
* <p>See issue: <a href="https://github.com/grpc/grpc-java/issues/1474">Improve unary server stub</a>
*/
@Override
public void post(Command request, StreamObserver<Ack> responseObserver) {
CommandClass commandClass = CommandClass.of(request);
Expand Down