# The hRPC Specification This document defines and explains design details for hRPC. ## Version This is hRPC specification version `1`. ## Protobuf Version All hRPC implementations **MUST** support [Protobuf 3](https://developers.google.com/protocol-buffers/docs/reference/proto3-spec). All references to Protobuf in this document are references to Protobuf 3. ## RPCs A unary RPC is where a Protobuf RPC signature is as follows: ```protobuf rpc ExampleMethod(ExampleMessage) returns (ExampleMessage); ``` A streaming RPC is where a Protobuf RPC signature is as follows: ```protobuf rpc ExampleMethod(stream ExampleMessage) returns (stream ExampleMessage); ``` A client streaming RPC is where a Protobuf RPC signature is as follows: ```protobuf rpc ExampleMethod(stream ExampleMessage) returns (ExampleMessage); ``` In client streaming RPCs, the server is only allowed to send **one** message. Messages sent after that **SHOULD** be ignored by the client. A server streaming RPC is where a Protobuf RPC signature is as follows: ```protobuf rpc ExampleMethod(ExampleMessage) returns (stream ExampleMessage); ``` In server streaming RPCs, the client is only allowed to send **one** message. Messages sent after that **SHOULD** be ignored by the server. ### Errors Servers can send errors to clients using the [hRPC error] protocol type. How errors sent are dependent on the transport used. Error identifiers are described in the [hRPC errors document]. ## Transports hRPC is transport agnostic. Here we describe transport specific design details. ### HTTP This transport works over HTTP. #### Request Paths A request path is a string in the following format, where `<package>` is the name of the package, `<service>` is the name of the service and `<rpc>` is the name of the RPC: ``` /<package>.<service>/<rpc> ``` If `<package>` is empty, it becomes the following: ``` /<service>/<rpc> ``` This is used as the path of an URI while making a request to a server. ##### Example For the Protobuf definition below: ```protobuf syntax = "proto3"; package example; message ExampleMessage { } service ExampleService { rpc ExampleMethod(ExampleMessage) returns (ExampleMessage); } ``` The `ExampleMethod` RPC will have a request path of: ``` /example.ExampleService/ExampleMethod ``` #### Unary RPCs ##### Unary requests - **MUST** have method set to `POST`. - **MUST** contain the serialized binary data of the Protobuf message in their body. - **MUST** set the [`Content-Type`][http headers] header to `application/hrpc`. - **MUST** set the [`Content-Length`][http headers] header to the length of the serialized binary data. - **SHOULD** add `<current spec version>` to `Hrpc-Version` header, where `<current spec version>` is the [version defined at the start of this document](#Version). ##### Unary responses - **MUST** contain the serialized binary data of the Protobuf message in their body. - **MUST** set the [`Content-Type`][http headers] header to `application/hrpc`. - **MUST** add `<current spec version>` to `Hrpc-Version` header, where `<current spec version>` is the [version defined at the start of this document](#Version). ##### Client behaviour - After getting a successful unary response, a client **SHOULD** look for the `Hrpc-Version` header. A client then **SHOULD** check if it can work with the version of the specification in the header. A client **SHOULD** return an error to the user notifying of the incompatible spec version. #### Streaming RPCs Streaming RPCs use a [`WebSocket`][websocket] to communicate Protobuf messages between server and client. The initial handshake is done through HTTP. ##### Handshake requests - **MUST** have method set to `GET`. - **MUST** contain `hrpc` in the [`Sec-WebSocket-Protocol`][websocket_protocol_header] header. - **SHOULD** add `hrpc-version=<current spec version>` to [`Sec-WebSocket-Extensions`][websocket_extensions_header] header, where `<current spec version>` is the [version defined at the start of this document](#Version). ##### Handshake responses - **IF** the request had `hrpc` in the [`Sec-WebSocket-Protocol`][websocket_protocol_header] header, **MUST** set the same header to `hrpc`. - **MUST** add `hrpc-version=<current spec version>` to [`Sec-WebSocket-Extensions`][websocket_extensions_header] header, where `<current spec version>` is the [version defined at the start of this document](#Version). ##### Client behaviour - After getting a successful handshake response from the server, a client **SHOULD** look for `hrpc-version=number` in the [`Sec-WebSocket-Extensions`][websocket_extensions_header] header. The `number` will be the version of hRPC implemented by the server. A client then **SHOULD** check if it can work with this version of the specification. If a client can't work with this version, it **SHOULD** close the [`WebSocket`][websocket]. - [`WebSocket` binary messages][websocket_messages] **MUST** be used to send RPCs request message in serialized form to the server. ##### Server behaviour - [`WebSocket` binary messages][websocket_messages] **MUST** be used to send RPCs response message or a [hRPC error] prefixed with an opcode. - If sending RPCs response message, the serialized message **MUST** be prefixed with `0`. - If sending a [hRPC error], the serialized error **MUST** be prefixed with `1`. ### Errors When a request fails for whatever reason, an error response should be sent. This applies to socket handshake requests and unary requests. Below should be implemented for error responses: - **MUST** set the body to a serialized [hRPC error] message. - **MUST** set the status to an **unsuccessful** [HTTP status]. This should be the status code corresponding to the error identifier. Implementations **MUST** use the [hRPC errors document] to decide what status to set. - **MUST** set the [`Content-Type`][http headers] header to `application/hrpc`. - **MUST** add `<current spec version>` to `Hrpc-Version` header, where `<current spec version>` is the [version defined at the start of this document](#Version). [http headers]: https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html [websocket]: https://datatracker.ietf.org/doc/html/rfc6455 [websocket_messages]: https://datatracker.ietf.org/doc/html/rfc6455#section-5.6 [websocket_protocol_header]: https://datatracker.ietf.org/doc/html/rfc6455#section-11.3.4 [websocket_extensions_header]: https://datatracker.ietf.org/doc/html/rfc6455#section-11.3.2 [hrpc error]: https://github.com/harmony-development/hrpc/blob/8e648895ece3eb1466f457125556cc86feeb92b3/protocol/hrpc.proto#L5-L13 [http status]: https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html [hrpc errors document]: a