-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
42 changed files
with
12,552 additions
and
7,121 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,255 @@ | ||
# Hiber API | ||
|
||
This is the protobuf specification of the Hiber GRPC API. | ||
|
||
Hiber also offers a limited, [read-only rest API](https://github.com/hiberglobal/rest-api) for convenience. | ||
This is based on the protobuf object definitions, but is (for now) mainly intended as a compatibility option | ||
to fetch messages and message events. | ||
|
||
## Technical tools | ||
|
||
### Protocol Buffers | ||
|
||
Protobuf is Google's replacement for JSON. | ||
Due to its use of binary buffers, it's a more efficient way to encode data than text based protocols (SOAP, JSON), especially in encoding integers. Fields are encoded through | ||
a 'tag', which are integers, which improves the density even more. | ||
|
||
There are protobuf libraries in most used languages, such as Java, JavaScript, Golang, C#, C, and C++. This makes adoption of the protocol really easy. | ||
Because server and client model are generated from the same source, there can be no confusion about the model. | ||
|
||
For more information, take a look at: | ||
|
||
- [Protobuf at Github](https://github.com/google/protobuf/wiki) | ||
- [Google Protocol Buffers Developer Guide](https://developers.google.com/protocol-buffers/) | ||
|
||
### GRPC | ||
|
||
GRPC is a way of defining rpc services in the protobuf format. | ||
GRPC is based on HTTP/2 and formalized the networking, status responses and streaming implementation for API calls. | ||
Because the specification generates both the client and server code, the specification is valid by default | ||
and API documentation is in one place. | ||
|
||
For more information, take a look at: | ||
|
||
- [GRPC Homepage](https://grpc.io/) | ||
- [GRPC Concepts](https://grpc.io/docs/guides/concepts.html) | ||
- [GRPC Language Guides](https://grpc.io/docs/) | ||
- [GRPC at Github](https://github.com/grpc/grpc) | ||
|
||
### GRPC Web | ||
|
||
Since GRPC is based on HTTP/2, it is not (yet) compatible with web browsers. | ||
In order to support web-based applications, we are running the grpc-web proxy. | ||
This allows GRPC calls from the browser, using the typescript code generated by the GRPC Web generator. | ||
|
||
For more information, take a look at: | ||
|
||
- [GRPC Web Specification](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md) | ||
- [GRPC Web on Github](https://github.com/improbable-eng/grpc-web/) | ||
|
||
(Note that Google has recently release [a beta version of their implementation of GRPC Web](https://github.com/grpc/grpc-web). | ||
We are looking into switching to that implementation in the future.) | ||
|
||
## Usage | ||
|
||
First of all, have a look through the .proto files in this repository. | ||
You will find that they are very easy to read, and we have tried to name everything as clearly as possible, | ||
so as to avoid unnecessary extra documentation. | ||
|
||
To use the proto files, clone this repository and generate code in your preferred language: | ||
|
||
- [C++](https://grpc.io/docs/tutorials/basic/c.html#generating-client-and-server-code) | ||
- [C#](https://grpc.io/docs/tutorials/basic/csharp.html#generating-client-and-server-code) | ||
- [Dart](https://grpc.io/docs/tutorials/basic/dart.html#generating-client-and-server-code) | ||
- [Go](https://grpc.io/docs/tutorials/basic/go.html#generating-client-and-server-code) | ||
- [Java](https://grpc.io/docs/tutorials/basic/java.html#generating-client-and-server-code) | ||
- [Node](https://grpc.io/docs/tutorials/basic/node.html#creating-the-client) | ||
- [Objective-C](https://grpc.io/docs/tutorials/basic/objective-c.html#generating-client-code) | ||
- [PHP](https://grpc.io/docs/tutorials/basic/php.html#generating-client-code) | ||
- [Python](https://grpc.io/docs/tutorials/basic/python.html#generating-client-and-server-code) | ||
- [Ruby](https://grpc.io/docs/tutorials/basic/ruby.html#generating-client-and-server-code) | ||
|
||
### Simple example | ||
|
||
For example: | ||
|
||
``` | ||
service CurrentUserService { | ||
rpc CurrentUser (CurrentUserRequest) returns (CurrentUser); | ||
} | ||
message CurrentUser { | ||
string id = 1; | ||
string email = 2; | ||
string name = 3; | ||
repeated string organizations = 4; | ||
} | ||
message CurrentUserRequest { | ||
} | ||
``` | ||
|
||
(Note that this is a reduced, and possibly outdated, example and you should consult the actual proto file for the actual, up to date definition.) | ||
|
||
This defines a service that has one rpc call, which expects an empty request object and returns a CurrentUser object. | ||
|
||
For API client purposes, you can mostly ignore the numbers and see this as a data class. | ||
Note the `repeated` keyword for the `organizations` field. This indicates that the field is of an array type (like `string[] organizations`). | ||
|
||
### List requests, selection objects and pagination | ||
|
||
For many of our list calls, which can list items like modems, users, etc., we use a selection object to | ||
simplify the filtering of the data. | ||
|
||
Since the same selection criteria can be used in different calls, selection objects are a simple way to | ||
extract this duplication out of the definitions. | ||
|
||
For example: | ||
|
||
``` | ||
service WebhookService { | ||
rpc List (ListRequest) returns (ListRequest.Response); | ||
} | ||
message Webhook { | ||
int64 id = 1; | ||
string organization = 2; | ||
string description = 3; | ||
repeated api.tag.Tag tags = 4; | ||
} | ||
message WebhookSelection { | ||
string description = 1; | ||
string url = 2; | ||
Filter.Webhooks webhooks = 3; | ||
api.tag.TagSelection tags = 4; | ||
} | ||
message ListRequest { | ||
message Response { | ||
repeated Webhook webhooks = 1; | ||
ListRequest request = 2; | ||
Pagination.Result pagination = 3; | ||
} | ||
string organization = 1; | ||
WebhookSelection selection = 2; | ||
Pagination pagination = 3; | ||
} | ||
message Pagination { | ||
message Result { | ||
int32 size = 1; | ||
int32 page = 2; | ||
int32 total = 3; | ||
int32 totalPages = 4; | ||
Pagination previous = 6; | ||
Pagination next = 7; | ||
} | ||
int32 size = 1; | ||
int32 page = 2; | ||
} | ||
``` | ||
|
||
(Note, again, that this is a reduced, and possibly outdated, example.) | ||
|
||
This code actually contains a few interesting things. First, nested messages. | ||
These are used to denoted linked function, i.e. the `Response` message inside the `ListRequest`. | ||
|
||
The `WebhookSelection` message contains the filters that can be applied to webhooks. | ||
Note that the `WebhookSelection` message contains a `TagSelection` as well. | ||
This is another selection object, used to filter webhooks by tags. | ||
|
||
The `Pagination` message is used to paginate the result. | ||
It's a simple page size and page number combination (where 0 is the first page). | ||
The `Pagination.Result` message also contains `size` and `page`, but has corrected the `size` field to a | ||
maximum value (or default value if it was 0). | ||
For convenience, it also contains a previous and next `Pagination` object, for easy pagination. | ||
|
||
Note that `ListRequest.Response` contains a `ListRequest`, which is a corrected version of the request. | ||
Selection object may have certain defaults or value limits, which will be visible in the corrected request. | ||
|
||
### Default values | ||
|
||
Everything in protobuf has a default value, which has a few interesting complications. | ||
|
||
For example: | ||
|
||
``` | ||
enum ContentType { | ||
DEFAULT = 0; | ||
JSON = 1; | ||
PROTO = 2; | ||
} | ||
``` | ||
|
||
Since protobuf has a default value for all objects, enum takes the first value as default value. | ||
To avoid the situation where omitting the field would still set a value, we've introduced the `DEFAULT` value. | ||
|
||
``` | ||
message UpdateBoolean { | ||
bool updated = 1; | ||
bool value = 2; | ||
} | ||
``` | ||
|
||
Since false is the default value for a boolean, we need to distinguish between an omitted value and | ||
setting the value to false in an update object. | ||
For this, we've added an `UpdateBoolean` message (and `UpdateClearableString` and `UpdateZeroableInt` | ||
for string that can be set to empty, and ints that can be set to 0, respectively) | ||
|
||
Usage is pretty simple, set a value in the object and set `updated` to true. | ||
|
||
### Versioning | ||
|
||
Protobuf/GRPC has a built-in versioning mechanism by using numbered fields. | ||
This essentially means that a field would change in a non-backwards compatible way, it would either be removed and added it with a new number, or deprecated and a new field with a new name would be added. | ||
In case of removal, the server is able to detect whether an old version is used and convert the field. | ||
|
||
For more information and a small number of examples, see the examples of versioning methods in the examples repo: [Versioning example](https://github.com/HiberGlobal/examples/tree/master/versioning) | ||
|
||
## Developing on our API | ||
|
||
For Hiber customer development, we have set up endpoints under [acc.env.hiber.cloud](https://acc.env.hiber.cloud): | ||
|
||
- [acc.env.hiber.cloud](https://acc.env.hiber.cloud): The Hiber web application | ||
- [api.acc.env.hiber.cloud](https://api.acc.env.hiber.cloud) (or [grpc.acc.env.hiber.cloud](https://grpc.acc.env.hiber.cloud)): | ||
The GRPC API, accessible over https on port 443 or 1443. | ||
(Note that opening this url in your browser will not work, since it requires HTTP2.) | ||
|
||
Notes: | ||
- This can be considered a stable production-like environment. | ||
- Technically, you might be able to connect a normal GRPC client to the GRPC Web API, but this is not recommended. | ||
|
||
### API Tokens | ||
|
||
The Hiber API requires a token for all GRPC calls, using a metadata field called `authorization` with value `bearer $YOUR_TOKEN_HERE`. | ||
|
||
To get a token for our API, go to the web application at [acc.env.hiber.cloud](https://acc.env.hiber.cloud) and log in. | ||
Once you are linked to an organization (this process is defined in the api, but not implemented in the web interface yet) | ||
you can create a token (using another token) on the API. | ||
|
||
(Note: for pilot customers, a number of tokens can be generated in advance, so this process is not necessary.) | ||
|
||
### Using our API in production | ||
|
||
For actual modems and modem messages, use [hiber.cloud](https://hiber.cloud): | ||
|
||
- [hiber.cloud](https://hiber.cloud): The Hiber web application | ||
- [api.hiber.cloud](https://api.hiber.cloud) (or [grpc.hiber.cloud](https://grpc.hiber.cloud)): | ||
The GRPC API, accessible over https on port 443 or 1443. | ||
(Note that opening this url in your browser will not work, since it requires HTTP2.) | ||
|
||
## Examples | ||
|
||
We've provided a collection of minimal examples in different languages in | ||
our [examples repository](https://github.com/HiberGlobal/examples). | ||
|
||
For initial development, to simplify client experimentation with our GRPC API, and as a server used by our examples, | ||
we've created a simple mock server that implements our API. | ||
It will return example data, and does not do any error handling aside from requiring that a token is present. | ||
|
||
For simple usage, you can simply pull the docker image at [hiberglobal/mock-server](https://hub.docker.com/r/hiberglobal/mock-server/) | ||
(most of the examples do this automatically when you run them). | ||
You can see the source code get some more information at [the mock-server folder in the examples repository](https://github.com/HiberGlobal/examples/blob/master/mock-server/). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
version: v1 | ||
name: buf.build/hiber/api | ||
breaking: | ||
use: | ||
- WIRE | ||
except: | ||
- FIELD_WIRE_COMPATIBLE_TYPE | ||
lint: | ||
use: | ||
- DEFAULT | ||
except: | ||
- ENUM_VALUE_PREFIX | ||
- DIRECTORY_SAME_PACKAGE | ||
- PACKAGE_SAME_JAVA_MULTIPLE_FILES # this works fine for Java | ||
- PACKAGE_DIRECTORY_MATCH | ||
- PACKAGE_VERSION_SUFFIX | ||
- RPC_RESPONSE_STANDARD_NAME | ||
- RPC_REQUEST_STANDARD_NAME | ||
- RPC_REQUEST_RESPONSE_UNIQUE | ||
ignore_only: | ||
# For C++ compatibility, enums in the same package can not have the same enum value names | ||
# This is mostly not an issue, since the values are mostly unique within a package, except for: | ||
# the unknown/unspecified zeroth enum value. | ||
# We should start making those unique. | ||
ENUM_ZERO_VALUE_SUFFIX: | ||
- assignment.proto | ||
- base.proto | ||
- easypulse.proto | ||
- event.proto | ||
- export.proto | ||
- field.proto | ||
- field_service.proto | ||
- integration_mqtt.proto | ||
- integration_slack.proto | ||
- map.proto | ||
- message.proto | ||
- modem.proto | ||
- modem_alarm.proto | ||
- modem_message_body_parser.proto | ||
- modem_message_downlink.proto | ||
- modem_transfer.proto | ||
- organization.proto | ||
- permission.proto | ||
- publisher.proto | ||
- subscription.proto | ||
- unit_preferences_service.proto | ||
- user.proto | ||
- value.proto | ||
- value_service.proto | ||
- webhook.proto | ||
# The sort enum is unique in its own right and doesn't need a suffix. | ||
- device_service.proto |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.