ServiceStack Raw Client query string - servicestack

This should be simple, but I must be using the wrong key words to find the answer.
How can I output the raw query string that the jsonserviceclient is generating when sending a request to the server? I know I could use fiddler or something else to snoop the answer to this, but I'm interested if there is something like:
var client = new JsonServiceClient("http://myService:port/");
var request = new MyOperation
{
SomeDate = DateTime.Today
};
Console.Out.Writeline(client.AsQueryString(request));

You can use the Reverse Routing extension methods to see what urls different populated Request DTOs would generate, e.g:
var relativeUrl = new MyOperation { SomeDate = DateTime.Today }.ToGetUrl();
var absoluteUrl = new MyOperation { SomeDate = DateTime.Today }.ToAbsoluteUri();

Related

How to add metadata to nodejs grpc call

I'd like to know how to add metadata to a nodejs grpc function call. I can use channel credentials when making the client with
var client = new proto.Document('some.address:8000',
grpc.credentials.createInsecure()
)
Which are send when using client.Send(doc, callback), but the go grpc server looks in the call metadata for identification information which I have to set. I tried using grpc.credentials.combineChannelCredentials with the insecure connection and a grpc.Metadata instance but I can't find the right way to do it.
The error I run into is TypeError: compose's first argument must be a CallCredentials object. I tried to follow it down but it goes into c code which loses me, I can't see what javascript type I have to give to comebineChannelCredentials to achieve what I'm looking for and the docs are a little sparse on how to achieve this.
You can pass metadata directly as an optional argument to a method call. So, for example, you could do this:
var meta = new grpc.Metadata();
meta.add('key', 'value');
client.send(doc, meta, callback);
For sake of completeness I'm going to extend on #murgatroid99 answer.
In order to attach metadata to a message on the client you can use:
var meta = new grpc.Metadata();
meta.add('key', 'value');
client.send(doc, meta, callback);
On the server side int your RPC method being called, when you want to grab your data you can use:
function(call, callback){
var myVals = call.metadata.get("key");
//My vals will be an array, so if you want to grab a single value:
var myVal = myVals[0];
}
I eventually worked it out through introspecting the grpc credentials code and modifying the implementation to expose an inner function. In the grpc module in the node_modules, file grpc/src/node/src/credentials.js add the line
exports.CallCredentials = CallCredentials;
after CallCredentials is imported. Then, in your code, you can write something like
var meta = grpc.Metadata();
meta.add('key', 'value');
var extra_creds = grpc.credentials.CallCredentials.createFromPlugin(
function (url, callback) {
callback(null, meta);
}
)
Then use extra_creds in the client builder
var creds = grpc.credentials.combineChannelCredentials(
grpc.credentials.createSsl(),
extra_creds,
)
Now you can make your client
var client = new proto.Document(
'some.address:8000',
creds,
)

Retrieve public statistics of video via youtube api

It's possible to obtain public statistics of video?
Using something like this i can get just total views of video and like count:
https://www.googleapis.com/youtube/v3/videos?part=statistics&key=API_KEY&id=ekzHIouo8Q4
It's possible to get those public statistics?
I found this question
Youtube GData API : Retrieving public statistics
But maybe something has changed?
The only API call under Version 3 of the API that will get you statistics is the
youtube.videos.list API
Try this API Explorer link to try:
https://developers.google.com/apis-explorer/#p/youtube/v3/youtube.videos.list?part=snippet%252C+statistics&id=Ys7-6_t7OEQ&maxResults=50&_h=2&
You can get those using Analytics API
Sample requests would help you understand.
Analytics API is a different service but libraries come in same package and you can use same authorization with adding "https://www.googleapis.com/auth/yt-analytics.readonly" scope
You would need to create YouTubeService object and can get search results for the keywords
YouTubeService youtubeService = new YouTubeService(new BaseClientService.Initializer()
{
ApiKey = "dfhdufhdfahfujashfd",
ApplicationName = this.GetType().ToString()
});
var searchListRequest = youtubeService.Search.List("snippet");
searchListRequest.Q = "cute cats";
searchListRequest.MaxResults = 10;
var searchListResponse = await searchListRequest.ExecuteAsync();
var videoId = searchListResponse.Items.First().Id.VideoId is the unique id of the video
// Video Request
VideosResource.ListRequest request = new VideosResource.ListRequest(youTubeService, "statistics")
{
Id = videoId
};
VideoListResponse response = request.Execute();
if (response.Items.First() != null && response.Items.First().Statistics != null)
{
Console.WriteLine(response.Items.First().Statistics.ViewCount);
}

how to post plain json data to service stack rest service

Below is the code I am using to post json data to a rest ful service
var client = new JsonServiceClient(BaseUri);
Todo d = new Todo(){Content = "Google",Order =1, Done = false };
var s = JsonSerializer.SerializeToString < Todo>(d);
// client.Post<string>("/Todos/", "[{\"content\":\"YouTube\"}]");
// string payload= "[{\"id\":2,\"content\":\"abcdef\",\"order\":1,\"done\":false}]";
// string payload = #"{""todo"":{ {""content"":""abcdef"",""order"":1}} }";
client.Post<string>("/todos/", s);
I tried passing plain json data , it keep on fialing with message "Bad data". Then i tried serizliing the entity that also didn't work.
You can use PostJsonToUrl, which is included in ServiceStack.Text.

Is there a more elegant way to build URIs in ServiceStack?

I'm building a Request/Acknowledge/Poll style REST service with NServiceBus underneath to manage queue processing. I want to give the client a URI to poll for updates.
Therefore I want to return a location header element in my web service as part of the acknowledgement. I can see that it is possible to do this:
return new HttpResult(response, HttpStatusCode.Accepted)
{
Location = base.Request.AbsoluteUri.CombineWith(response.Reference)
}
But for a Url such as: http://localhost:54567/approvals/?message=test, which creates a new message (I know I should probably just use a POST), the location will be returned as: http://localhost:54567/approvals/?message=test/8f0ab1c1a2ca46f8a98b75330fd3ac5c.
The ServiceStack request doesn't expose the Uri fragments, only the AbsouteUri. This means that I need to access the original request. I want this to work regardless of whether this is running in IIS or in a self hosted process. The closest I can come up with is the following, but it seems very clunky:
var reference = Guid.NewGuid().ToString("N");
var response = new ApprovalResponse { Reference = reference };
var httpRequest = ((System.Web.HttpRequest)base.Request.OriginalRequest).Url;
var baseUri = new Uri(String.Concat(httpRequest.Scheme, Uri.SchemeDelimiter, httpRequest.Host, ":", httpRequest.Port));
var uri = new Uri(baseUri, string.Format("/approvals/{0}", reference));
return new HttpResult(response, HttpStatusCode.Accepted)
{
Location = uri.ToString()
};
This now returns: http://localhost:55847/approvals/8f0ab1c1a2ca46f8a98b75330fd3ac5c
Any suggestions? Does this work regardless of how ServiceStack is hosted? I'm a little scared of the System.Web.HttpRequest casting in a self hosted process. Is this code safe?
Reverse Routing
If you're trying to build urls for ServiceStack services you can use the RequestDto.ToGetUrl() and RequestDto.ToAbsoluteUri() to build relative and absolute urls as seen in this earlier question on Reverse Routing. e.g:
[Route("/reqstars/search", "GET")]
[Route("/reqstars/aged/{Age}")]
public class SearchReqstars : IReturn<ReqstarsResponse>
{
public int? Age { get; set; }
}
var relativeUrl = new SearchReqstars { Age = 20 }.ToUrl("GET");
var absoluteUrl = HostContext.Config.WebHostUrl.CombineWith(relativeUrl);
relativeUrl.Print(); //= /reqstars/aged/20
absoluteUrl.Print(); //= http://www.myhost.com/reqstars/aged/20
For creating Urls for other 3rd Party APIs look at the Http Utils wiki for example extension methods that can help, e.g:
var url ="http://api.twitter.com/user_timeline.json?screen_name={0}".Fmt(name);
if (sinceId != null)
url = url.AddQueryParam("since_id", sinceId);
if (maxId != null)
url = url.AddQueryParam("max_id", maxId);
var tweets = url.GetJsonFromUrl()
.FromJson<List<Tweet>>();
You can also use the QueryStringSerializer to serialize a number of different collection types, e.g:
//Typed POCO
var url = "http://example.org/login?" + QueryStringSerializer.SerializeToString(
new Login { Username="mythz", Password="password" });
//Anonymous type
var url = "http://example.org/login?" + QueryStringSerializer.SerializeToString(
new { Username="mythz", Password="password" });
//string Dictionary
var url = "http://example.org/login?" + QueryStringSerializer.SerializeToString(
new Dictionary<string,string> {{"Username","mythz"}, {"Password","password"}});
You can also serialize the built-in NameValueCollection.ToFormUrlEncoded() extension, e.g:
var url = "http://example.org/login?" + new NameValueCollection {
{"Username","mythz"}, {"Password","password"} }.ToFormUrlEncoded();

Apache Thrift with nodejs example

I am trying to use Apache Thrift for passing messages between applications implemented in different languages. It is not necessarily used as RPC, but more for serializing/deserializing messages.
One application is in node.js. I am trying to figure out how Apache thrift works with node.js, but I can't find too much documentation and examples, except for one tiny one regarding Cassandra at:
https://github.com/apache/thrift/tree/trunk/lib/nodejs
Again, I don't need any procedures declared in the .thrift file, I only need to serialize a simple data structure like:
struct Notification {
1: string subject,
2: string message
}
Can anyone help me with an example?
I finally found the answer to this question, after wasting a lot of time just by looking at the library for nodejs.
//SERIALIZATION:
var buffer = new Buffer(notification);
var transport = new thrift.TFramedTransport(buffer);
var binaryProt = new thrift.TBinaryProtocol(transport);
notification.write(binaryProt);
At this point, the byte array can be found in the transport.outBuffers field:
var byteArray = transport.outBuffers;
For deserialization:
var tTransport = new thrift.TFramedTransport(byteArray);
var tProtocol = new thrift.TBinaryProtocol(tTransport);
var receivedNotif = new notification_type.Notification();
receivedNotif.read(tProtocol);
Also the following lines need to be added to the index.js file from the nodejs library for thrift:
exports.TFramedTransport = require('./transport').TFramedTransport;
exports.TBufferedTransport = require('./transport').TBufferedTransport;
exports.TBinaryProtocol = require('./protocol').TBinaryProtocol;
Plus there is also at least one bug in the nodejs library.
The above answer is wrong, because it tries to use outBuffers directly, which is an array of buffers. Here is a working example of using thrift with nodejs:
var util = require('util');
var thrift = require('thrift');
var Notification = require('./gen-nodejs/notification_types.js').Notification;
var TFramedTransport = require('thrift/lib/thrift/transport').TFramedTransport;
var TBufferedTransport = require('thrift/lib/thrift/transport').TBufferedTransport;
var TBinaryProtocol = require('thrift/lib/thrift/protocol').TBinaryProtocol;
var transport = new TFramedTransport(null, function(byteArray) {
// Flush puts a 4-byte header, which needs to be parsed/sliced.
byteArray = byteArray.slice(4);
// DESERIALIZATION:
var tTransport = new TFramedTransport(byteArray);
var tProtocol = new TBinaryProtocol(tTransport);
var receivedNotification = new Notification();
receivedUser.read(tProtocol);
console.log(util.inspect(receivedNotification, false, null));
});
var binaryProt = new TBinaryProtocol(transport);
// SERIALIZATION:
var notification = new Notification({"subject":"AAAA"});
console.log(util.inspect(notification, false, null));
notification.write(binaryProt);
transport.flush();
DigitalGhost is right, the previous example is wrong.
IMHO the outBuffers is a private property to the transport class and should not be accessed.

Resources