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

what is the best way to expose http rest api from grpc server #8659

Closed
SanZhiYuan opened this issue Nov 4, 2021 · 4 comments
Closed

what is the best way to expose http rest api from grpc server #8659

SanZhiYuan opened this issue Nov 4, 2021 · 4 comments
Labels

Comments

@SanZhiYuan
Copy link

hi,

for some reasons I need to expose some http rest apis from an existing gRPC server, and an external reverse proxy like envy is not an option. so I tried these implementations with SpringBoot and AbstractProcessor, receive an http request, convert request to protobuf, init Context, call gRPC, convert observer protobuf to response, send it back, etc.

  1. in generated-sources call gRPC service implementation directly, but failed to spread Context into gRPC service implementation
  2. in generated-sources call gRPC service implementation through IPC server and channel, from the documentation
   String uniqueName = InProcessServerBuilder.generateName();
   Server server = InProcessServerBuilder.forName(uniqueName)
       .directExecutor() // **directExecutor is fine for unit tests**
       .addService(/* your code here */)
       .build().start();
   ManagedChannel channel = InProcessChannelBuilder.forName(uniqueName)
       .directExecutor()
       .build();

My question is which one is better, if the first one, how to share Context; if the second, is directExecutor() still fine in this use case? and how about the performance lose?

thanks a lot

@sergiitk
Copy link
Member

sergiitk commented Nov 5, 2021

Depends on what you're building, it might make sense to move actual implementation, and then make gRPC service impl and your http adaptor call it. This is, obviously, the most performant approach.

class Api extends ApiGrpc.ApimplBase {
  @Override
  public void hello(HelloRequest req, StreamObserver<ApiReply> responseObserver) {
    ApiReply reply = ApiReply.newBuilder().setResult(ApiImpl.hello(req)).build();
    responseObserver.onNext(reply);
    responseObserver.onCompleted();
  }
}

@RestController
public class ApiAdapterController {
  @GetMapping("/hello")
  public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
   // build HelloRequest
   String result = ApiImpl.hello(req);
   // return result obj
 }
}

class ApiImpl {
  public static String hello(HelloRequest req) {
    // do work
    return "Hello  " + req.name;
  }
}

@sergiitk
Copy link
Member

sergiitk commented Nov 5, 2021

Otherwise, the recommended approach is using IPC, and the direct executor. One caveat with this setup: if you're building bidi streaming, be aware of #3084. Since you're building http API adapter, this shouldn't affect you. Unless you're planning on proxying web sockets, or similar.

@SanZhiYuan
Copy link
Author

Depends on what you're building, it might make sense to move actual implementation, and then make gRPC service impl and your http adaptor call it. This is, obviously, the most performant approach.

class Api extends ApiGrpc.ApimplBase {
  @Override
  public void hello(HelloRequest req, StreamObserver<ApiReply> responseObserver) {
    ApiReply reply = ApiReply.newBuilder().setResult(ApiImpl.hello(req)).build();
    responseObserver.onNext(reply);
    responseObserver.onCompleted();
  }
}

@RestController
public class ApiAdapterController {
  @GetMapping("/hello")
  public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
   // build HelloRequest
   String result = ApiImpl.hello(req);
   // return result obj
 }
}

class ApiImpl {
  public static String hello(HelloRequest req) {
    // do work
    return "Hello  " + req.name;
  }
}

this comes as the first thought, but I could not find an entrance to convert http headers to gRPC Context, so finally the IPC way has been implemented, which I can easily transfer http headers to Meta within client interceptor, and it's all about some POST functions, thanks for the tip.
thanks a lot

@sergiitk
Copy link
Member

sergiitk commented Nov 8, 2021

Happy to help.

@sergiitk sergiitk closed this as completed Nov 8, 2021
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 7, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

2 participants