If I have a simple unary gRPC function. Say the protobuf file looks like
message Request {
string very_long_string = 1;
}
service MyService {
rpc MyRPC(Request) returns (Response) {};
}
On the server when I use the generated implementation for this, the function header will look something like
grpc::Status MyRPC(grpc::ServerContext* context, const Request* request,
Response* response) override
In general I like that the request is const. However I would like a way to move the string ('very_long_string' above) OUT of the request instead of making a copy of it. I seem to be able to do it if I const_cast the request then use the protobuf release function on the very_long_string value. However is there a better way to do this? Also if there is NOT a better way to do this does gRPC require that the request is not modified in any way? Will removing const cause any problems?
Related
As part of a POC, I’m using spring-cloud-function with spring-cloud-function-adapter-aws to expose a function behind an AWS ALB, that looks up a business object and returns it. However, in the event of a missing object I’m struggling to understand which function signature to use that allows me to return a 404 status code with an empty payload.
I’ve tried a few options, such as Function<APIGatewayProxyRequestEvent, Owner> and Function<APIGatewayProxyRequestEvent, Message<Owner>>. The former doesn’t let you control statusCode and headers that are returned, and the latter doesn’t let you return a Message with a null payload.
I’ve landed on Function<APIGatewayProxyRequestEvent, Message<String>> getOwnerById() which allows me to specify a statusCode and an empty string as the body, but I’m wondering if there’s a more idiomatic approach to this in spring-cloud-function that allows me to return an empty body?
Ideally, I’d just like to return a APIGatewayProxyResponseEvent, which I’d have full control of and would bypass all post-function response conversion.
I have my solution in GitHub, with the function and a test which reproduces the issue
https://github.com/foyst/spring-petclinic-rest-serverless/blob/1-spring-cloud-function/src/main/java/org/springframework/samples/petclinic/lambda/LambdaConfig.java
https://github.com/foyst/spring-petclinic-rest-serverless/blob/1-spring-cloud-function/src/test/java/org/springframework/samples/petclinic/lambda/LambdaConfigTests.java
Thanks in advance!
My middleware need is to:
add an extra query param to requests made by a REST API client derived from GuzzleHttp\Command\Guzzle\GuzzleClient
I cannot do this directly when invoking APIs through the client because GuzzleClient uses an API specification and it only passes on "legal" query parameters. Therefore I must install a middleware to intercept HTTP requests after the API client prepares them.
The track I am currently on:
$apiClient->getHandlerStack()-push($myMiddleware)
The problem:
I cannot figure out the RIGHT way to assemble the functional Russian doll that $myMiddleware must be. This is an insane gazilliardth-order function scenario, and the exact right way the function should be written seems to be different from the extensively documented way of doing things when working with GuzzleHttp\Client directly. No matter what I try, I end up having wrong things passed to some layer of the matryoshka, causing an argument type error, or I end up returning something wrong from a layer, causing a type error in Guzzle code.
I made a carefully weighted decision to give up trying to understand. Please just give me a boilerplate solution for GuzzleHttp\Command\Guzzle\GuzzleClient, as opposed to GuzzleHttp\Client.
The HandlerStack that is used to handle middleware in GuzzleHttp\Command\Guzzle\GuzzleClient can either transform/validate a command before it is serialized or handle the result after it comes back. If you want to modify the command after it has been turned into a request, but before it is actually sent, then you'd use the same method of Middleware as if you weren't using GuzzleClient - create and attach middleware to the GuzzleHttp\Client instance that is passed as the first argument to GuzzleClient.
use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Command\Guzzle\GuzzleClient;
use GuzzleHttp\Command\Guzzle\Description;
class MyCustomMiddleware
{
public function __invoke(callable $handler) {
return function (RequestInterface $request, array $options) use ($handler) {
// ... do something with request
return $handler($request, $options);
}
}
}
$handlerStack = HandlerStack::create();
$handlerStack->push(new MyCustomMiddleware);
$config['handler'] = $handlerStack;
$apiClient = new GuzzleClient(new Client($config), new Description(...));
The boilerplate solution for GuzzleClient is the same as for GuzzleHttp\Client because regardless of using Guzzle Services or not, your request-modifying middleware needs to go on GuzzleHttp\Client.
You can also use
$handler->push(Middleware::mapRequest(function(){...});
Of sorts to manipulate the request. I'm not 100% certain this is the thing you're looking for. But I assume you can add your extra parameter to the Request in there.
private function createAuthStack()
{
$stack = HandlerStack::create();
$stack->push(Middleware::mapRequest(function (RequestInterface $request) {
return $request->withHeader('Authorization', "Bearer " . $this->accessToken);
}));
return $stack;
}
More Examples here: https://hotexamples.com/examples/guzzlehttp/Middleware/mapRequest/php-middleware-maprequest-method-examples.html
I found a few examples of using fullRequestInterceptor and httpConfig.timeout to allow canceling requests in restangular.
example 1 | example 2
this is how I'm adding the interceptor:
app.run(function (Restangular, $q) {
Restangular.addFullRequestInterceptor(function (element, operation, what, url, headers, params, httpConfig) {
I managed to abort the request by putting a resolved promise in timeout (results in an error being logged and the request goes out but is canceled), which is not what I want.
What I'm trying to do - I want to make the AJAX request myself with my own requests and pass the result back to whatever component that used Restangular. Is this possible?
I've been looking a restangular way to solve it, but I should have been looking for an angular way :)
Overriding dependency at runtime in AngularJS
Looks like you can extend $http before it ever gets to Restangular. I haven't tried it yet, but it looks like it would fit my needs 100%.
I'm using requestInterceptor a lot, but only to change parameters and headers of my request.
Basically addFullRequestInterceptor is helping you making change on your request before sending it. So why not changing the url you want to call ?
There is the httpConfig object that you can modify and return, and if it's close to the config of $http (and I bet it is) you can change the url and even method, and so change the original request to another one, entirely knew.
After that you don't need timeout only returning an httpConfig customise to your need.
RestangularConfigurer.addFullRequestInterceptor(function (element, operation, route, url, headers, params, httpConfig) {
httpConfig.url = "http://google.com";
httpConfig.method = "GET";
httpConfig.params = "";
return {
httpConfig: httpConfig
};
});
It will be pass on and your service or controller won't know that something change, that's the principle of interceptor, it allow you to change stuff and returning to be use by the next process a bit like a middleware. And so it will be transparent to the one making the call but the call will be made to what you want.
I'm experiencing unexpected behaviour while trying to access query string parameters in a mojolicious websocket request. Say my request looks like this:
ws://127.0.0.1:3000/websock_action?item_id=1234
Then in my mojo controller code I try and get the value of item_id in any of the following ways:
#in mojo controller
my $item_id = $self->param('item_id');
my $item_id = scalar $self->param('item_id');
my $item_id = scalar $self->tx->req->url->query->param('item_id');
The issue is that the item_id I get is often from a previous request, whichever of these techniques I use. My app is currently being served with hypnotoad.
Are query string parameters supported on websocket requests in mojolicious? Is there a more reliable way to access them? Essentially I'd like to know if I'm trying to something that isn't supported, so I can know whether the problem is something specific to my app.
Thanks in advance for any help
I suspect that what is happening, is that the parameters are passed in the html request, which is then upgraded to a websocket request at which point they are no longer available.
As Daren said, pass the data in the Web-Socket data. Something like...
var ws = $.websocket("ws://127.0.0.1:3000/websock_action", {
events: { message: function(e) {}
});
ws.send('message', 1234);
I'm having trouble setting something up that I'm pretty sure /should/ be easy, so I thought I'd throw it to the crowd. I can't seem to find what I'm looking for elsewhere on the web or on SE.
I am simplifying my project of course, but basically I have a JAX-WS annontated Jersey resource class that looks something like this:
#Path("myresource")
public class MyResource {
#Autowired
MyComplexObjectDAO daoInstance;
#Path("findObject/{id}")
#GET
public MyComplexObject findObject( #PathParam(value="id") String id ) {
return daoInstance.findObject( id );
}
#Path("saveObject")
#PUT
public MyComplexObject saveObject( MyComplexObject objectToSave ) {
MyComplexObject savedObject = daoInstance.saveObject( objectToSave );
return savedObject;
}
}
So you can see I'm autowiring a DAO object using spring, and then I use the DAO methods in the REST handlers.
The 'findObject' call seems to work fine - so far it works exactly as I expect it to.
The 'saveObject' call is not working the way I want and that's what I need some advice on.
You can see that I'm trying to directly take an instance of my complex object as a parameter to the REST method. Additionally I would like to return an instance of the complex object after it's been saved.
I put together some 'client' code for testing this out.
#Test
public void saveTest() {
WebResource wsClient = createWebServiceClient();
MyComplexObject unsavedInstance = createMyComplexObject();
MyComplexObject savedInstance =
wsClient
.path("saveObject")
.accept(MediaType.APPLICATION_XML)
.put(MyComplexObject.class, unsavedInstance);
assertNotNull(savedIntent);
}
Which is returning the following error:
com.sun.jersey.api.client.UniformInterfaceException: PUT http://localhost:8081/rest/myresource/save returned a response status of 400 Bad Request
I don't see why this isn't working and I think I've tried just about everything I can think of. Any help or direction would be very much appreciated.
Thanks so much!
I see that you call the accept() method in your test client (which means that a "Accept:" header is added to the request, indicating the server what type of representation you would like). However, you don't call the type() method to add a "Content-type:" header and inform the server that you are sending XML data. See http://jersey.java.net/nonav/documentation/latest/client-api.html#d4e644 for examples.
Side remark: your URLs are not RESTful - you should avoid verbs in your path:
So, instead of:
/api/findObject/{id}
/api/saveObject
You should use:
/api/objects/{id}
/api/objects
Last note: to create an object on calling /api/objects, you should do a POST and not a PUT to adhere to REST best practices and widely adopted patterns.
switching to the 'concrete class' solution I alluded to in my earlier comment is what fixed things up for me.