-
Notifications
You must be signed in to change notification settings - Fork 8
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
Setup starter, ci and implemented POC / Unary Call. #8
Conversation
8dd1769
to
9da53f8
Compare
src/decorators/rpc.decorator.ts
Outdated
@@ -0,0 +1,35 @@ | |||
// Copyright IBM Corp. 2017. All Rights Reserved. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we name it grpc.decorator.ts
?
src/decorators/rpc.decorator.ts
Outdated
* } | ||
* } | ||
*/ | ||
export function rpc() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
grpc
?
@@ -0,0 +1,56 @@ | |||
// Copyright IBM Corp. 2017. All Rights Reserved. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
grpc?
@jonathan-casarrubias Great start! I added a few minor comments. |
@raymondfeng thanks for reviewing, also let me elaborate why I'm using rpc. What we are actually implementing with the @rpc decorator are RPC Methods (gRPC stands for the entire RPC System), IMO following semantics would help understand easier to people the reading of the GRPC documentation vs LB4 implementation. For instance, the entire module is named grpc.component which attempts to achieve the entire gRPC functionality, rpc stands just for RPC methods. Thoughts? |
I see. With more extensions contributing decorators, there are potentially name conflicts. Maybe we should use a namespace such as |
@raymondfeng I see your point too and for that I have a couple of notes 1.- I see a little odd -but possible- people using 2 RPC systems within LB at the same time. But if that is the case, then: import {rpc as grpc} from '@loopback/grpc';
import {rpc as orpc} from '@other/orpc'; That way the decorator maintains the original semantic and package conflicts would be fixed at imports. Maybe I'm being to squared in terms of semantics, but I still think that can be easily fixed using what I describe above, at the end.... They -the developers- would also be able to import another grpc package that would conflict with the decorator and the fix would be the same I describe above. for instance, importing the grpc module Anyway if you still believe @grpc is better for any reason, then we can just change that and won't hurt that much :P as if we throw the rest of the code away.... lol Thoughts? |
I'm leaning toward
|
@raymondfeng ok cool, lets do that then... I'll change to grpc all around. Cheers! |
9da53f8
to
86ddab5
Compare
@raymondfeng I just did those changes and squached the commit... Now everything related to the decorator is referenced as grpc instead of rpc. cheers 😄 |
86ddab5
to
798b023
Compare
@jonathan-casarrubias would you mind moving the project-setup-related changes to a standalone PR, so that we can land it quickly and get those changes out of our way? Quite often, I review pull requests in whole, and it costs me a lot of time and energy to always skip changes that are not important for the feature being implemented. |
IMO, package-lock is pretty harmful when developing modules. When you clone this repo and install dependencies, you get the locked down version of the deps, which is different from the versions that will be installed by our users, when they install this module from npm. What's even worse, our CI will do the same, therefore we will be testing our code against a different set of dependencies that our actual users will use. The solution: add |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great start!
src/decorators/README.md
Outdated
*/ | ||
@grpc() | ||
public sayHello(call, callback) { | ||
callback(null, {message: 'Hello ' + call.request.name}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have two comments about this example.
-
How is
Greeter#sayHello
linked to the correct service/procedure from the proto file? -
It's the task of the transport layer to convert the transport-specific request data into typed and validated arguments of a controller method. The controller methods should not need to deal with low-level transport-specific API like
call.request.name
, this should be handled by the framework.
class MyController implements Greeter {
sayHello({name}: HelloRequest): HelloResponse {
return {message: `hello ${name}`};
}
}
Here are some of the benefits of this approach:
- The user can focus on writing the business logic in typescript/javascript, possibly in a transport-independent way.
- Because both request and response are typed (based on the information we already have in the
.proto
file), the TypeScript compiler can catch many errors at compile time.
it('defines reflection metadata for rpc method', () => { | ||
class Greeter implements GreeterInterface { | ||
@grpc() | ||
SayHello(request: HelloRequest): HelloReply { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! This is what I was looking for in my previous comment. Looks like the implementation is good but the README needs an update?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes the readme is the one outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done I updated the docs and addressed the rest of the comments, I'm landing this PR now :)
const flags: {[key: string]: boolean} = {}; | ||
const app: Application = givenApplication(); | ||
app.controller(Greeter); | ||
const controller = app.find('controllers.Greeter').pop(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this code is living in the file called grpc.decorator.unit.ts
, it should contain a unit test that's testing the decorator in isolation, stubbing any dependencies as needed. You should not be using the full Application object! Unfortunately, we are behind on docs for extension developers (see loopbackio/loopback-next#579), but some relevant information can be found in these places:
- http://loopback.io/doc/en/lb4/Testing-your-application.html#types-of-tests
- http://loopback.io/doc/en/lb4/Testing-your-application.html#unit-testing
In this particular case, just scan Greeter.prototype
directly.
let controllerMethods: string[] = [];
const flags: {[key: string]: boolean} = {};
const proto = Greeter.prototype;
// ...
} | ||
expect(controllerMethods).to.eql(['SayHello', 'Helper']); | ||
expect(flags.SayHello).to.be.true(); | ||
expect(flags.Helper).to.be.undefined(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When something goes wrong here, e.g. there is a typo in SayHello
, then these two checks won't provide enough information to troubleshoot the problem.
A better approach is to use deepEqual
and test the whole object.
expect(flags).to.deepEqual({
SayHello: true,
// Helper: ignored
});
test/unit/grpc.component.unit.ts
Outdated
describe('GrpcComponent', () => { | ||
// GRPC Component Configurations | ||
it('defines grpc component configurations', async () => { | ||
const app: Application = givenApplication(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto - unit tests should not depend on other objects like Application
. I think you should move this file to test/acceptance/grpc.component.acceptance.ts
.
@virkt25 you have the most practical experience with testing a component. What's your recommendation - how to test the component itself?
798b023
to
fc64d21
Compare
Implemented a vanilla version of the loopback extension starter, made some tweaks and added travis & appveyor config files. Added lint fix to pretest Implemented grpc Decorator Implemented grpc server provider Implemented grpc server Implemented grpc sequence Implemented grpc bindings Implemented grpc configs Implemented unit tests - Fix: #7 - Fix: #4 - Fix: #3
fc64d21
to
10bd14c
Compare
Implemented a vanilla version of the loopback extension
starter, made some tweaks and added travis & appveyor config files.
Added lint fix to pretest
Implemented grpc Decorator
Implemented grpc server provider
Implemented grpc server
Implemented grpc sequence
Implemented grpc bindings
Implemented grpc configs
Implemented unit tests