Gaia, the very framework to make gRPC services
Project description
gaia
Gaia, the very framework to make gRPC services. Gaia defines a definitely intuitive way to write gRPC services.
- Handle Custom Errors
gRPC
does NOT provide an formal way to handle errors, even lack of documentation, whilegaia
will do it for you. - Manage
.proto
filesgaia
allows us to share proto files between server and clients.gaia
sharesgPRC
protobuf files by wrapping them into an npm package and publishing the npm tarball to npm registry. - Eggjs compatible plugins
gaia
supports to use egg plugins to extend your applications. - Restful API service made easy
gaia
provides a convenient way to define restful API routings upon the existing gRPC services.
gaia
supports both proto2 and proto3.
Install
$ npm i gaia
Table of Contents
Synopsis
const {
Server,
Client,
resolvePackage
} = require('gaia')
const root = path.join(__dirname, 'example', 'hello')
To make better understanding the usage of gaia
, the example below is based on the demo in the
example/hello
directory.
Start server:
new Server(root).listen(50051)
Run client:
const {
// service Greeter
Greeter
} = new Client(root).connect('localhost:50051')
const run = async () => {
const {message} = await Greeter.sayHello({name: 'world'})
console.log(message)
}
run()
// Hello world
APIs
new Client(root)
Creates the gaia client.
- root
path
the root path to load the client from
client.connect(host):
Connects to the gRPC server and returns the service methods
- host
string
the server host to connect to which includes the server hostname and port and whose pattern is<hostname>:<port>
new Server(root, serverConfig?)
- root
path
the root path to load the server from - serverConfig?
ServerConfig={}
server configurations
interface ServerConfig {
// Defines where to load controllers
controller_root?: string = 'controller'
plugins?: Array<Plugin>
services?: Services
}
interface Package {
// The root path of the package
path?: string
// The package name of the package
package?: string
// Either path or package should be defined.
}
interface Plugin extends Package {
// Configurations for the plugin
config: object
}
interface Service extends Package {
// the host param of `client.connect(host)`
host: string
}
interface Services {
[name: string]: Service
}
server.listen(port): this
- port
number
the port which gRPC server will listen to.
Start the gaia server.
server.kill()
Forcibly shut down the gRPC server
await server.close()
Gracefully shut down the server
resolvePackage(id: string): string
- id
string
package id
Returns the root path of the package
new Client(resolvePackage('foo')).connect(host)
How gaia
makes .proto
files sharable and portable?
gaia
takes full advantage of npm packages to share proto files.
A minimun gaia
service portable, as well as service hello
or package hello
, could be:
/path/to/hello/
|-- proto/
| |-- hello.proto
|-- package.json
And in proto/hello.proto
:
syntax = "proto3";
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
package.json
{
"name": "hello",
"gaia": {
...
}
}
The the optional field "gaia"
of package.json follows the schema:
interface FieldGaia {
// Tells `gaia` which properties of error should be
// - collected, serialized and transmitted to the clients.
// - or deseriialized from server
// `errorProps` defaults to `['code', 'message']`
// if the server throws an `error`, by default, gaia will collect
// - `error.code`,
// - `error.message`
// and send them to its clients, while other properties will be omitted.
errorProps?: Array<string> = ['code', 'message']
// Specifies where to load proto files.
// `protoPath` should be a relative path to `root`
protoPath?: string = 'proto'
// Proto filenames inside `protoPath`.
// If not specified, gaia will search all `*.proto` files inside `protoPath`.
protos?: Array<string> | string = '*.proto'
// See section #import-proto-files-from-hello below
protoDependencies?: Array<string> = []
}
Apparently, package hello
has everything we need to create a client agent for service hello
.
And package hello
is language-independent which only contains proto files and client configurations.
Create the client of hello
Assume that we have a new project foo
, and we npm install hello
.
/path/to/foo/
|-- proto/
| |-- foo.proto
|-- node_modules/
| |-- hello/
|-- package.json
Then if the hello
service is already running on port 8000
, we could create a hello client by following lines:
const {Client} = require('gaia')
const {Greeter} = new Client('/path/to/foo/node_modules/hello').connect('localhost:8000')
Import .proto
files from hello
Since project foo
, as we introduced above, has a dependency hello
, we could import .proto
files from package hello
.
in /path/to/foo/proto/foo.proto
:
syntax = "proto3";
// We could install a package and import things from it
// as well as we do in JavaScript es modules. Oh yeah! 😆
import "hello/proto/hello.proto"
service FooGreeter {
// We could reuse message types from package `hello`
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
In order to do that, we need to declare that hello
is a gaia
dependency of foo
by adding some fields in package.json:
{
"name": "foo",
"gaia": {
// So that we could import .proto files from package `hello`
"protoDependencies": [
// We have to add "hello" here.
"hello"
]
},
"dependencies": {
// This is generated by `npm install`
"hello": "^1.0.0"
}
}
And gaia
will manage the --proto_path
s (includeDirs) for you, so that gRPC Protobuf Loader will know where to search and import .proto
files
More about includeDirs
gaia
recursively parses the protoDependencies
of project foo
, and its protoDependency
's protoDependencies
to generate the options.includeDirs
option for @grpc/proto-loader
How to Write a gaia
Server
Take the project hello
which introduced above for example.
Since we define a Greeter
service in hello.proto
, we must implement the corresponding controller by ourselves.
Service controllers should be defined in directory /path/to/hello/controller
which can be changed with by config controller_root
.
We must provide a Greeter.js
in that directory.
/path/to/hello/
|-- controller/
| |-- Greeter.js
in Greeter.js
, there should be an async/sync method named SayHello
in exports
because we defined a SayHello
rpc method in service Greeter
exports.sayHello = ({name}) => ({
message: `Hello ${name}`
})
Packages and name resolution
First the innermost package scope is searched, then the next-innermost, and so on, and at last the service name.
Assume that we have the following protocol buffer.
package foo.bar;
service Baz {
rpc Quux (Req) returns (Res) {}
}
Then in directory controller_root
, we need to create a JavaScript file foo/bar/Baz.js
whose exports
has a Quux
method.
this
object of the controller methods
There are several properties could be access by this
object of the controller methods.
Reusing other controllers
We could access other controller methods by
this.controller[namespace0][namespace1]...[serviceName][methodName]
For example, we could access the Quux
method by
exports.OtherMethodsOfSomeService = async function (request) {
const data = await this.controller.foo.bar.Baz.Quux(request)
// ...
return something
}
Using external services
If we provide serverConfig.services
for server
new Server('/path/to/service/foo', {
...otherConfig,
services: {
hello: {
// 'hello' is a gaia server
package: 'hello'
}
}
})
.listen(port)
Then, client of the service 'hello'
could be accessed from the service controller of foo by:
exports.Quux = async function ({name}) {
const {message} = await this.service.hello.SayHello({name})
return {
property: message
}
}
Using plugins
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file gaia.py-0.1.0.tar.gz
.
File metadata
- Download URL: gaia.py-0.1.0.tar.gz
- Upload date:
- Size: 7.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.23.0 setuptools/45.2.0.post20200210 requests-toolbelt/0.9.1 tqdm/4.43.0 CPython/3.8.1
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | ecb8586d10d2e8e07d46f02305632dae8f03f92afd2cfd8ac5fbeeee14003977 |
|
MD5 | 7b3b90b047b484606b61e37a83943da6 |
|
BLAKE2b-256 | d384d82a5b449ac3b07ae8be2122047baa52fa99c4a0d2d4fbfd823da73211b6 |
File details
Details for the file gaia.py-0.1.0-py3-none-any.whl
.
File metadata
- Download URL: gaia.py-0.1.0-py3-none-any.whl
- Upload date:
- Size: 6.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.23.0 setuptools/45.2.0.post20200210 requests-toolbelt/0.9.1 tqdm/4.43.0 CPython/3.8.1
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 15fd8cfa6675bcc077c25fb03e770ed4c647be8f340a5da81b73f135cbd7c9b6 |
|
MD5 | b787bc134a2e00d05ab021cf1e6d4cc8 |
|
BLAKE2b-256 | f2d8b0440ed8f5a9f37faf041072a9ac9ed3ad262c5f52ce470be074200c99ad |