best practices Google+ programming: developers documentation google programming
by gguuss
leave a comment
Making the most of the Google+ developer site
The curse of knowledge – knowing something and then not realizing that you have this knowledge – can make it difficult to remember the first time that you started learning about something. A great example of this is the Google developer documentation. Virtually every set of developer documentation that I have used and contributed to has been unique to the site or project that I have been working on and Google+ is no exception. This is not by design, writers spend hours, weeks, even months planning and mapping out how the documentation will be organized based on how the user will learn from it and how they will find the things that they are looking for. Documentation organization and information architecture are extremely difficult and no particular solution is best.
In this blog post I’ll try and summarize a few key points of how you can use the Google+ developer documentation that I have learned from using it constantly.
A high level overview
In case you have missed it, the Google+ Developer site is at https://developers.google.com/+.
The most important part of being a power user of the Google+ documentation is to understand the navigation bar on the left and what the blocks of content represent. The following diagram summarizes each section:

- At the top, you have the most effective resources for getting started. These cover the “what is it” and “how do I see it work” topics. I’ll refer to this as the getting started section.
- Next, you have a breakdown of Google+ by feature and platform. I’ll just call this section features and platforms.
- Next, you have a breakdown of the developer resources that are quick references for the top resources that developers are looking for. I like to think of this as “get the stuff” but really it’s better summarized as Top Resources.
- Finally, you have the community updates and other broader information for Google+ developers. This is the external/community resource section for Google+.
Given that breakdown, you can jump into each section with some sort of expectations and understanding for what you will encounter. I’ll now dive deeper into each section.
Getting Started
This section covers the first resources that you will want to get to know and experiment with the product. This is breadth content that is not specific to a feature but is generalized to a high level view of the Google+ platform. The key content here is:
- A quick platform overview for Google+.
- Getting started samples. We call these the quickstarts because they should get you going in around 10 minutes. These are broken down by platform / programming language (Android, iOS, Python, etc).
- The Photohunt sample. This is our showcase demo that brings together the features into something interesting and also demonstrates best practices for end-to-end applications built on Google+.
- The API reference that lets you understand the full capabilities of the Google+ API platform.
When you dive into this content, you are typically looking to understand the platform overall and quickly get going. When you reach this content, it’s assumed that you want to experiment and explore by diving right into using the platform.
Features and Platforms
This section covers each part of the platform atomically and is the most visually focused content on the developer site. You can look at all of the available features to understand them as well as how to use them. There is a ton of content in this section that is essential to understanding and using the platform. You can also learn about why each feature and platform is useful for you. It’s broken down to cover:
- Google+ features breakdown by capabilities. Here you can learn all about the core platform features of Google+. Sign-in, interactive posts, app activities, over-the-air installs, and so on.
- iOS and Android mobile platforms
- Hangouts
You can think of this section as a palette from which you can paint products. Each of these components is available and summarized for you to understand how it can work for you. Each of the sections contains code and examples ready to copy and paste. When you’re looking for a solution provided by the product / Google+ platform, this is where you go. When you want to see a feature and then jump in to understand how to use it, you can find everything right here. To discover the relevant content you can either dive right in to the platform that you are using, click through the visual content to the highlighted buttons on the top of the page.
Top resources
This section covers much of the “Get it now” contents and resources that can be shared with external folks you are working with.
From this section you can get:
- The API and SDK resources in the Download section
- The top best practices content
- The Branding Guidelines for designing custom UI that conforms to Google+ branding
If you are looking for resources to point agencies to, these are the important ones. If you are looking to get the components for building apps, this is also where you should look.
External / Community for Google+
These links cover the topics for being good citizens in the Google+ ecosystem and getting involved with the exciting things that are going on with Google+. From this section, you will find resources to:
- External and First party Google+ communities. We put our Google+ Developers Live videos here along with links to our Google+ community for Google+ Developers, our Google+ Developers page, our tag on Stack Overflow, and our official Google+ GitHub page.
- The Google+ platform issue tracker for bug reporting and feature requests
- Release notes for enthusiasts and folks who need to track changes as they are released.
- Developer policies and terms of service so that you can be a good citizen in the Google+ ecosystem.
When you are looking to maintain a deep understanding of Google+ and are getting to a more mature state with Google+ development, these sections are essential. You can connect with other people who are developing with Google+, can find resolutions to specific problems, and can learn the intricacies of how we want developers to use Google+.
Thoughts and Conclusions
I know that most people reach our content through search. However, it can be really useful to get acquainted with the layout of our developer content so that you can also explore and discover the relevant content for your Google+ integration. The Google+ content team of writers has put immense amounts of effort into making our site as useful as possible for developers, take advantage of all the work they’ve put in! I’ll add a few more summaries to help you understand a few key things that you should look at and will reference over the course of your career as a Google+ developer.
Requirements for developing with Google+:
API Overviews:
- The full Google+ API Reference
- The Hangouts API reference
- The iOS API reference
- The Android API reference
Code:
Please contribute to making the site better through the issue tracker and by telling the Google+ developer team what you think on the Google+ developers page. The feedback that goes through these channels really and truly shapes the future of the platform and the Google+ developer content.
A final note, all of the latest Google+ features are being covered at Google IO this week. Follow the Google+ track either at the conference, at IO extended meetups, or online to learn all of the great new opportunities that are possible with Google+.
The curse of knowledge – knowing something and then not realizing that you have this knowledge – can make it difficult to remember the first time that you started learning about something. A great example of this is the Google developer documentation. Virtually every set of developer documentation that I have used and contributed to has been unique to the site or project that I have been working on and Google+ is no exception. This is not by design, writers spend hours, weeks, even months planning and mapping out how the documentation will be organized based on how the user will learn from it and how they will find the things that they are looking for. Documentation organization and information architecture are extremely difficult and no particular solution is best.
In this blog post I’ll try and summarize a few key points of how you can use the Google+ developer documentation that I have learned from using it constantly.
A high level overview
In case you have missed it, the Google+ Developer site is at https://developers.google.com/+.
The most important part of being a power user of the Google+ documentation is to understand the navigation bar on the left and what the blocks of content represent. The following diagram summarizes each section:

- At the top, you have the most effective resources for getting started. These cover the “what is it” and “how do I see it work” topics. I’ll refer to this as the getting started section.
- Next, you have a breakdown of Google+ by feature and platform. I’ll just call this section features and platforms.
- Next, you have a breakdown of the developer resources that are quick references for the top resources that developers are looking for. I like to think of this as “get the stuff” but really it’s better summarized as Top Resources.
- Finally, you have the community updates and other broader information for Google+ developers. This is the external/community resource section for Google+.
Given that breakdown, you can jump into each section with some sort of expectations and understanding for what you will encounter. I’ll now dive deeper into each section.
Getting Started
This section covers the first resources that you will want to get to know and experiment with the product. This is breadth content that is not specific to a feature but is generalized to a high level view of the Google+ platform. The key content here is:
- A quick platform overview for Google+.
- Getting started samples. We call these the quickstarts because they should get you going in around 10 minutes. These are broken down by platform / programming language (Android, iOS, Python, etc).
- The Photohunt sample. This is our showcase demo that brings together the features into something interesting and also demonstrates best practices for end-to-end applications built on Google+.
- The API reference that lets you understand the full capabilities of the Google+ API platform.
When you dive into this content, you are typically looking to understand the platform overall and quickly get going. When you reach this content, it’s assumed that you want to experiment and explore by diving right into using the platform.
Features and Platforms
This section covers each part of the platform atomically and is the most visually focused content on the developer site. You can look at all of the available features to understand them as well as how to use them. There is a ton of content in this section that is essential to understanding and using the platform. You can also learn about why each feature and platform is useful for you. It’s broken down to cover:
- Google+ features breakdown by capabilities. Here you can learn all about the core platform features of Google+. Sign-in, interactive posts, app activities, over-the-air installs, and so on.
- iOS and Android mobile platforms
- Hangouts
You can think of this section as a palette from which you can paint products. Each of these components is available and summarized for you to understand how it can work for you. Each of the sections contains code and examples ready to copy and paste. When you’re looking for a solution provided by the product / Google+ platform, this is where you go. When you want to see a feature and then jump in to understand how to use it, you can find everything right here. To discover the relevant content you can either dive right in to the platform that you are using, click through the visual content to the highlighted buttons on the top of the page.
Top resources
This section covers much of the “Get it now” contents and resources that can be shared with external folks you are working with.
From this section you can get:
- The API and SDK resources in the Download section
- The top best practices content
- The Branding Guidelines for designing custom UI that conforms to Google+ branding
If you are looking for resources to point agencies to, these are the important ones. If you are looking to get the components for building apps, this is also where you should look.
External / Community for Google+
These links cover the topics for being good citizens in the Google+ ecosystem and getting involved with the exciting things that are going on with Google+. From this section, you will find resources to:
- External and First party Google+ communities. We put our Google+ Developers Live videos here along with links to our Google+ community for Google+ Developers, our Google+ Developers page, our tag on Stack Overflow, and our official Google+ GitHub page.
- The Google+ platform issue tracker for bug reporting and feature requests
- Release notes for enthusiasts and folks who need to track changes as they are released.
- Developer policies and terms of service so that you can be a good citizen in the Google+ ecosystem.
When you are looking to maintain a deep understanding of Google+ and are getting to a more mature state with Google+ development, these sections are essential. You can connect with other people who are developing with Google+, can find resolutions to specific problems, and can learn the intricacies of how we want developers to use Google+.
Thoughts and Conclusions
I know that most people reach our content through search. However, it can be really useful to get acquainted with the layout of our developer content so that you can also explore and discover the relevant content for your Google+ integration. The Google+ content team of writers has put immense amounts of effort into making our site as useful as possible for developers, take advantage of all the work they’ve put in! I’ll add a few more summaries to help you understand a few key things that you should look at and will reference over the course of your career as a Google+ developer.
Requirements for developing with Google+:
API Overviews:
- The full Google+ API Reference
- The Hangouts API reference
- The iOS API reference
- The Android API reference
Code:
Please contribute to making the site better through the issue tracker and by telling the Google+ developer team what you think on the Google+ developers page. The feedback that goes through these channels really and truly shapes the future of the platform and the Google+ developer content.
A final note, all of the latest Google+ features are being covered at Google IO this week. Follow the Google+ track either at the conference, at IO extended meetups, or online to learn all of the great new opportunities that are possible with Google+.
best practices patterns Plus programming: best practices javascript programming
by gguuss
leave a comment
Google API clients: Why you should use them and how
Some of our older code examples, including many that I have authored on my blog have been using raw query execution against the Google APIs. This is undesirable and is absolutely not a best practice because you will not benefit from the convenience and reliability that comes with using methods on the API.
The beauty of the Google APIs is that they use a discovery service that allows Google and third parties to generate updated packages on the fly for developers to consume in their target languages. What this means is that as the APIs change, the client libraries will automatically be updated to support these changes. Furthermore, these client libraries are owned and tested by Google making them much more stable and reliable than using raw access to the API endpoints.
In this post, I’ll show you first a few bad examples for queries and will show you better ways of accessing Google’s APIs.
The first culprit: client request execution
The Google API clients support performing raw execution against the Google APIs using appropriate network stacks for that particular client. This is great design because client queries can share the same execution code and benefit from improvements in caching, performance, reliability, and so forth. Additionally, the API will manage authorization and will manage your bearer token for you. However, accessing the APIs in this manner requires you to parse and manage JSON objects which can introduce bugs and support issues for you, the developer.
For example, in this post, I run the following code (do not do this):
var payload = {
"target": {
"id" : "replacewithuniqueidforaddtarget",
"image" : "http://www.google.com/s2/static/images/GoogleyEyes.png",
"type" : "http://schema.org/CreativeWork",
"description" : "The description for the activity",
"name":"An example of AddActivity"
},
"type":"http://schemas.google.com/AddActivity",
"startDate": "2012-10-31T23:59:59.999Z"
};
var args = {
'path': '/plus/v1/people/me/moments/vault',
'method': 'POST',
'body': JSON.stringify(payload),
'callback': function(response) {
console.log(response);
}
};
gapi.client.request(args);
What this code is doing is directly POSTing JSON data to the API endpoint. This is undesirable because there are a number of ways that things can go wrong and you must write loads of unnecessary and difficult to read code. In addition, you have to stringify the API call when you make it and also parse the response from the query.
Next culprit: XHR / RAW HTTP requests
This is actually worse than the first culprit: rolling your own client using the XHR object in JavaScript. The following example, from code I wrote roughly a year ago, illustrates what not to do (DO NOT DO THIS):
// globals used for auth, showing debugging
var debug = true;
var key = "AIzaSyC63QTL6Brw_4IQFK6uKRQDj-KmGPKMwnA";
function handleRequestIssue(request){
// For now, just can cry about it..
console.log("khhhhaaaaann!!!, status:" + request.status + " / response:" + request.responseText);
}
// Gets the activities for a profile
function getActivities(profileID){
var activities = null;
var URL = "https://www.googleapis.com/plus/v1/people/" + profileID + "/activities/public?alt=json&key=" + key;
var request = new XMLHttpRequest();
request.open('GET', URL, false);
request.send(); // because of "false" above, will block until the request is done
// and status is available. Not recommended, however it works for simple cases.
if (request.status === 200) {
if (debug) console.log("retrieved activities nn");
if (debug) console.log("rawnn" + request.responseText);
activities = jQuery.parseJSON(request.responseText).items;
console.log("Discovered " + activities.length + " activities");
console.log("raw:" + request.responseText);
}else{
handleRequestIssue(request);
}
return activities;
}
function getCommentsForActivity(activityID){
var comments = "";
var URL = "https://www.googleapis.com/plus/v1/activities/" + activityID + "/comments?alt=json&key=" + key;
var request = new XMLHttpRequest();
request.open('GET', URL, false);
request.send(); // because of "false" above, will block until the request is done
// and status is available. Not recommended, however it works for simple cases.
if (request.status === 200) {
if (debug) console.log(request.responseText);
comments = jQuery.parseJSON(request.responseText).items;
if (debug){
for (comment in comments){
console.log(comment);
}
}
}else{
handleRequestIssue(request);
}
return comments;
}
function manualTrigger(){
var activities = getActivities("109716647623830091721");
}
As you can see, this code is even less readable than the first set of code! I’m even adding an ugly and blatantly terrible error handler that lacks remediation for the response issues. The code is super fragile: changes at multiple points in the process will introduce bugs in my demo. Do not access the APIs this way.
Doing it RIGHT: The Google API Clients
Here is the best way to do this: using the Google API clients and accessing the functionality and data through the API client. The following JavaScript example lists comments from the current user’s stream and can be seen here: Demo: listing comments (DO IT THIS WAY):
<html>
<script>
var output;
function signinCallback(result){
console.log(result);
if (result.access_token != null){
// success
document.getElementById('signinButton').style.display = 'none';
output = document.getElementById('output');
}
// Load the client library and call getActivities once it's loaded
gapi.client.load('plus', 'v1', getActivities);
}
// Gets the activities for a profile using the client library
function getActivities(){
var activities = null;
gapi.client.plus.activities.list({'userId' : 'me'}).execute(
function(activities){
console.log(activities);
for (var index = 0; index < activities.items.length; index++){
output.value += 'nn-------n' + JSON.stringify(activities.items[index]);
output.innerText = output.innerText + JSON.stringify;
getCommentsForActivity(activities.items[index].id);
}
});
}
function getCommentsForActivity(activityID){
gapi.client.plus.comments.list(
{'activityId' : activityID}).
execute(
function(comment){
output.value += 'n' + JSON.stringify(comment);
console.log(comment);
});
}
</script>
<body>
<span id="signinButton">
<span
class="g-signin"
data-callback="signinCallback"
data-clientid="1065047579848.apps.googleusercontent.com"
data-cookiepolicy="single_host_origin"
data-scope="https://www.googleapis.com/auth/plus.login">
</span>
</span>
<textarea cols="80" rows="40" id="output">
</textarea>
<!-- Place this asynchronous JavaScript just before your </body> tag -->
<script type="text/javascript">
(function() {
var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
po.src = 'https://apis.google.com/js/client:plusone.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
})();
</script>
</body>
</html>
See how much better it is! This code is even doing MORE than the other code in fewer lines. You get nice objects and methods for all of the operations performed on Google+ and the code will be updated from Google if anything ever changes. By accessing the API in this manner, you will be getting all of the client library updates by loading the client library from Google and will get a reliable means of accessing the API functionality.
The Google+ quickstarts show how to use the client libraries in a number of languages, this is a great way to get started with understanding the relevant patterns for your language of choice. Also, this is a great way to learn how to perform the operations in a language you understand less because the samples are virtually identical in all languages.
Conclusion
Although it may seem obvious now, always make sure that you use the Google API clients when programming against the Google APIs. There is a client for virtually every language out there to make your code more maintainable, stable, performant, and readable. The API clients support much more than I covered here that makes your life easier. Many other great examples of client execution can be found on Ian Barber’s blog. For example, the following article shows how to use the API client to batch API calls:
The generic Google client libraries that use the discovery service can be found at:
You can also download the Google+ API clients from the Google+ developer pages that are targeted to Google+.
For certain languages such as C# and Java, the client libraries must be generated, so occasionally it may be a good idea to update your clients if you’re using these languages. Have fun accessing the APIs, and be sure to do it the right way, using the freely available clients!
Some of our older code examples, including many that I have authored on my blog have been using raw query execution against the Google APIs. This is undesirable and is absolutely not a best practice because you will not benefit from the convenience and reliability that comes with using methods on the API.
The beauty of the Google APIs is that they use a discovery service that allows Google and third parties to generate updated packages on the fly for developers to consume in their target languages. What this means is that as the APIs change, the client libraries will automatically be updated to support these changes. Furthermore, these client libraries are owned and tested by Google making them much more stable and reliable than using raw access to the API endpoints.
In this post, I’ll show you first a few bad examples for queries and will show you better ways of accessing Google’s APIs.
The first culprit: client request execution
The Google API clients support performing raw execution against the Google APIs using appropriate network stacks for that particular client. This is great design because client queries can share the same execution code and benefit from improvements in caching, performance, reliability, and so forth. Additionally, the API will manage authorization and will manage your bearer token for you. However, accessing the APIs in this manner requires you to parse and manage JSON objects which can introduce bugs and support issues for you, the developer.
For example, in this post, I run the following code (do not do this):
var payload = {
"target": {
"id" : "replacewithuniqueidforaddtarget",
"image" : "http://www.google.com/s2/static/images/GoogleyEyes.png",
"type" : "http://schema.org/CreativeWork",
"description" : "The description for the activity",
"name":"An example of AddActivity"
},
"type":"http://schemas.google.com/AddActivity",
"startDate": "2012-10-31T23:59:59.999Z"
};
var args = {
'path': '/plus/v1/people/me/moments/vault',
'method': 'POST',
'body': JSON.stringify(payload),
'callback': function(response) {
console.log(response);
}
};
gapi.client.request(args);
What this code is doing is directly POSTing JSON data to the API endpoint. This is undesirable because there are a number of ways that things can go wrong and you must write loads of unnecessary and difficult to read code. In addition, you have to stringify the API call when you make it and also parse the response from the query.
Next culprit: XHR / RAW HTTP requests
This is actually worse than the first culprit: rolling your own client using the XHR object in JavaScript. The following example, from code I wrote roughly a year ago, illustrates what not to do (DO NOT DO THIS):
// globals used for auth, showing debugging
var debug = true;
var key = "AIzaSyC63QTL6Brw_4IQFK6uKRQDj-KmGPKMwnA";
function handleRequestIssue(request){
// For now, just can cry about it..
console.log("khhhhaaaaann!!!, status:" + request.status + " / response:" + request.responseText);
}
// Gets the activities for a profile
function getActivities(profileID){
var activities = null;
var URL = "https://www.googleapis.com/plus/v1/people/" + profileID + "/activities/public?alt=json&key=" + key;
var request = new XMLHttpRequest();
request.open('GET', URL, false);
request.send(); // because of "false" above, will block until the request is done
// and status is available. Not recommended, however it works for simple cases.
if (request.status === 200) {
if (debug) console.log("retrieved activities nn");
if (debug) console.log("rawnn" + request.responseText);
activities = jQuery.parseJSON(request.responseText).items;
console.log("Discovered " + activities.length + " activities");
console.log("raw:" + request.responseText);
}else{
handleRequestIssue(request);
}
return activities;
}
function getCommentsForActivity(activityID){
var comments = "";
var URL = "https://www.googleapis.com/plus/v1/activities/" + activityID + "/comments?alt=json&key=" + key;
var request = new XMLHttpRequest();
request.open('GET', URL, false);
request.send(); // because of "false" above, will block until the request is done
// and status is available. Not recommended, however it works for simple cases.
if (request.status === 200) {
if (debug) console.log(request.responseText);
comments = jQuery.parseJSON(request.responseText).items;
if (debug){
for (comment in comments){
console.log(comment);
}
}
}else{
handleRequestIssue(request);
}
return comments;
}
function manualTrigger(){
var activities = getActivities("109716647623830091721");
}
As you can see, this code is even less readable than the first set of code! I’m even adding an ugly and blatantly terrible error handler that lacks remediation for the response issues. The code is super fragile: changes at multiple points in the process will introduce bugs in my demo. Do not access the APIs this way.
Doing it RIGHT: The Google API Clients
Here is the best way to do this: using the Google API clients and accessing the functionality and data through the API client. The following JavaScript example lists comments from the current user’s stream and can be seen here: Demo: listing comments (DO IT THIS WAY):
<html>
<script>
var output;
function signinCallback(result){
console.log(result);
if (result.access_token != null){
// success
document.getElementById('signinButton').style.display = 'none';
output = document.getElementById('output');
}
// Load the client library and call getActivities once it's loaded
gapi.client.load('plus', 'v1', getActivities);
}
// Gets the activities for a profile using the client library
function getActivities(){
var activities = null;
gapi.client.plus.activities.list({'userId' : 'me'}).execute(
function(activities){
console.log(activities);
for (var index = 0; index < activities.items.length; index++){
output.value += 'nn-------n' + JSON.stringify(activities.items[index]);
output.innerText = output.innerText + JSON.stringify;
getCommentsForActivity(activities.items[index].id);
}
});
}
function getCommentsForActivity(activityID){
gapi.client.plus.comments.list(
{'activityId' : activityID}).
execute(
function(comment){
output.value += 'n' + JSON.stringify(comment);
console.log(comment);
});
}
</script>
<body>
<span id="signinButton">
<span
class="g-signin"
data-callback="signinCallback"
data-clientid="1065047579848.apps.googleusercontent.com"
data-cookiepolicy="single_host_origin"
data-scope="https://www.googleapis.com/auth/plus.login">
</span>
</span>
<textarea cols="80" rows="40" id="output">
</textarea>
<!-- Place this asynchronous JavaScript just before your </body> tag -->
<script type="text/javascript">
(function() {
var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
po.src = 'https://apis.google.com/js/client:plusone.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
})();
</script>
</body>
</html>
See how much better it is! This code is even doing MORE than the other code in fewer lines. You get nice objects and methods for all of the operations performed on Google+ and the code will be updated from Google if anything ever changes. By accessing the API in this manner, you will be getting all of the client library updates by loading the client library from Google and will get a reliable means of accessing the API functionality.
The Google+ quickstarts show how to use the client libraries in a number of languages, this is a great way to get started with understanding the relevant patterns for your language of choice. Also, this is a great way to learn how to perform the operations in a language you understand less because the samples are virtually identical in all languages.
Conclusion
Although it may seem obvious now, always make sure that you use the Google API clients when programming against the Google APIs. There is a client for virtually every language out there to make your code more maintainable, stable, performant, and readable. The API clients support much more than I covered here that makes your life easier. Many other great examples of client execution can be found on Ian Barber’s blog. For example, the following article shows how to use the API client to batch API calls:
The generic Google client libraries that use the discovery service can be found at:
You can also download the Google+ API clients from the Google+ developer pages that are targeted to Google+.
For certain languages such as C# and Java, the client libraries must be generated, so occasionally it may be a good idea to update your clients if you’re using these languages. Have fun accessing the APIs, and be sure to do it the right way, using the freely available clients!
CSharp productivity programming: C# development I can't believe it's not Visual Studio programming
by gguuss
1 comment
Developing in C# from OS X using MonoDevelop
Before we begin, you can get MonoDevelop from here: MonoDevelop
I have been playing a little bit with MonoDevelop as an alternative to running a VM from OS X for C# development. After spending a little time with it, MonoDevelop really isn’t that bad…
(I can hear the *hissing* from naysayers)
… Really! It’s not Visual Studio, mind you, but it’s still a great IDE. For OS X, the latest versions have pretty awesome coverage of the .NET 4.0 specification and C# 4. Even a good portion of the .NET 4.5 specification is supported and C# 5 is on the way!
I’ll go over a few things that I really like and don’t like about the experience so far.
The Good
Code completion is extremely boss in MonoDevelop. Here you can see the type-ahead completion and extracted documentation rendering in the IDE while I code:
I love this type of code completion. Even the most tepid command-line programmers can’t poo-poo this kind of functionality.
The Solution View – navigating your files
Next, the IDE does this wonderful thing where only one project is open at a time and provides a clear “solution” view as well as other useful perspectives for viewing, editing, and debugging projects.
Just like Visual Studio, you can see all of the projects and resources associated with your solution and can easily manage them. Projects unrelated to what you are doing are not cluttering your workspace and sucking up valuable space in your IDE.
Debugging
Here you can see code with a breakpoint and interactive debugging being performed from MonoDevelop, it’s very slick!
Here you can see the watch and immediate windows, you might exclaim, “I can’t believe it’s not Visual Studio! Same great taste!”
Overall, the MonoDevelop team has the basics covered and much more, even approaching into addressing all the “nice to have” things as well.
The Bad
Some core library and developer functionality just plain isn’t there. I’m not sure if it’s Mono, MonoDevelop, OS X, or gremlins, but there are certain times that you will see things like this:
Most of the time, this doesn’t affect you, the coverage that you get on the Mono platform is surprisingly good.
The Ugly
If you are trying to run newer versions of MonoDevelop on a Ubuntu distribution, you’re gonna have a bad time. The latest official version of Mono that ships in Ubuntu is 2.08 and I don’t know how long it will be until official support will be available for newer versions – I’m looking at you versions 2.11+, which include native support for Entity Framework.
Regardless of your Mono version, you will sometimes have to do weird things to get your code working. This could be due to programmer laziness because Visual Studio is basically cruise control + autopilot for programmers or it could be due to the very heterogeneous environments in which Mono(Develop) runs in. Regardless of the cause, you have to do some magic bone waving in order to get your project running if you created it on Windows with Visual Studio.
Using MonoDevelop in practice
Speaking of magic bone waving, I got the Google+ C#/.NET Quickstart working from MonoDevelop on OS X! I only had to do one little trick to get DotNetOpenAuth to stop complaining… the following steps should be enough to get you going:
Follow the same instructions as the quickstart except:
- Download the log4net library
- Place the extracted DLL from the Mono folder into the services folder alongside the other libraries
- Profit!
When you run the sample, the server will not by default go to the http://localhost:4567/signin.aspx page. Instead, it will load on the default development port, 8080, and will navigate to index.html the template file used for the project. The easiest way to get around these two things:
- Add http://localhost:8080 to your project in the Google APIs console
- Manually enter the URL http://localhost:8080 into your browser when the code runs
That’s it!
Feel free to let me know what you think of MonoDevelop and whether you have any tips for using it, my first foray into using it has shown this to be a very promising, intuitive, and clean IDE. If only I could develop and manage Java projects with such a nice UI and the wonderful code completion and documentation integration…
Before we begin, you can get MonoDevelop from here: MonoDevelop
I have been playing a little bit with MonoDevelop as an alternative to running a VM from OS X for C# development. After spending a little time with it, MonoDevelop really isn’t that bad…
(I can hear the *hissing* from naysayers)
… Really! It’s not Visual Studio, mind you, but it’s still a great IDE. For OS X, the latest versions have pretty awesome coverage of the .NET 4.0 specification and C# 4. Even a good portion of the .NET 4.5 specification is supported and C# 5 is on the way!
I’ll go over a few things that I really like and don’t like about the experience so far.
The Good
Code completion is extremely boss in MonoDevelop. Here you can see the type-ahead completion and extracted documentation rendering in the IDE while I code:
I love this type of code completion. Even the most tepid command-line programmers can’t poo-poo this kind of functionality.
The Solution View – navigating your files
Next, the IDE does this wonderful thing where only one project is open at a time and provides a clear “solution” view as well as other useful perspectives for viewing, editing, and debugging projects.
Just like Visual Studio, you can see all of the projects and resources associated with your solution and can easily manage them. Projects unrelated to what you are doing are not cluttering your workspace and sucking up valuable space in your IDE.
Debugging
Here you can see code with a breakpoint and interactive debugging being performed from MonoDevelop, it’s very slick!
Here you can see the watch and immediate windows, you might exclaim, “I can’t believe it’s not Visual Studio! Same great taste!”
Overall, the MonoDevelop team has the basics covered and much more, even approaching into addressing all the “nice to have” things as well.
The Bad
Some core library and developer functionality just plain isn’t there. I’m not sure if it’s Mono, MonoDevelop, OS X, or gremlins, but there are certain times that you will see things like this:
Most of the time, this doesn’t affect you, the coverage that you get on the Mono platform is surprisingly good.
The Ugly
If you are trying to run newer versions of MonoDevelop on a Ubuntu distribution, you’re gonna have a bad time. The latest official version of Mono that ships in Ubuntu is 2.08 and I don’t know how long it will be until official support will be available for newer versions – I’m looking at you versions 2.11+, which include native support for Entity Framework.
Regardless of your Mono version, you will sometimes have to do weird things to get your code working. This could be due to programmer laziness because Visual Studio is basically cruise control + autopilot for programmers or it could be due to the very heterogeneous environments in which Mono(Develop) runs in. Regardless of the cause, you have to do some magic bone waving in order to get your project running if you created it on Windows with Visual Studio.
Using MonoDevelop in practice
Speaking of magic bone waving, I got the Google+ C#/.NET Quickstart working from MonoDevelop on OS X! I only had to do one little trick to get DotNetOpenAuth to stop complaining… the following steps should be enough to get you going:
Follow the same instructions as the quickstart except:
- Download the log4net library
- Place the extracted DLL from the Mono folder into the services folder alongside the other libraries
- Profit!
When you run the sample, the server will not by default go to the http://localhost:4567/signin.aspx page. Instead, it will load on the default development port, 8080, and will navigate to index.html the template file used for the project. The easiest way to get around these two things:
- Add http://localhost:8080 to your project in the Google APIs console
- Manually enter the URL http://localhost:8080 into your browser when the code runs
That’s it!
Feel free to let me know what you think of MonoDevelop and whether you have any tips for using it, my first foray into using it has shown this to be a very promising, intuitive, and clean IDE. If only I could develop and manage Java projects with such a nice UI and the wonderful code completion and documentation integration…
android Google Google+ howtos java Plus programming: android google java programming
by gguuss
leave a comment
Targeting Interactive Post recipients in Android
In the April 9th, 2013 Google+ Developers Live, Chirag and I demonstrated how to set the recipients for an Interactive Post in Android. You can watch the video below:
Code from the show
I have added a gist to GitHub for the code showing how I targeted Android interactive shares by combining the listPeopleActivity into the ShareActivity. The following snippets cover the relevant code changes relative to the Android quickstart sample:
Adding the PlusClient.OnPeopleLoadedListenter interface, for the asynchronous method from loadPeople:
public class ShareActivity extends FragmentActivity implements View.OnClickListener,
OnSignedInListener,
PlusClient.OnPeopleLoadedListener
{
A few variables for holding the PlusClient, used for getting the Interactive Share intent, and the ArrayList of people, populated in the onPeopleLoaded callback.
// Add lists for holding the people from people.list
private ArrayList<Person> mBestRecipients;
private PlusClient mPlusClient;
The onPeopleLoaded asynchronous callback implementation:
// The onPeopleLoaded method for the callback handling the response when the visible
// people are listed
@Override
public void onPeopleLoaded(ConnectionResult status, PersonBuffer personBuffer,
String nextPageToken) {
if (status.getErrorCode() == ConnectionResult.SUCCESS) {
mBestRecipients.clear();
try {
int count = personBuffer.getCount();
for (int i = 0; i < count; i++) {
Person toAdd = personBuffer.get(i).freeze();
mBestRecipients.add(toAdd);
}
} finally {
personBuffer.close();
}
} else {
Log.e(TAG, "Error when listing people: " + status);
}
Intent intent = getInteractivePostIntent(mPlusClient);
startActivityForResult(intent, REQUEST_CODE_INTERACTIVE_POST);
}
The code for adding the recipients to the post:
if (best){
// Use the recipients list created from people.list...best
builder.setRecipients(mBestRecipients);
}
Additional Notes, Errata
There were a few topics that we would have liked to cover in the episode but just didn’t have enough time for, ended up getting glossed over, or might have been lost when we had recorded live.
While I was setting up the APIs console, I mentioned putting in a meaningful name for the project name. What I should have indicated was to use an appropriate brand name for your company and an appropriate name for this particular client ID. When you are setting up the project, you want to make sure to get this right because it can be difficult to change it later on.
I really would have liked to show adding specific users by name. For example, I was missing Chirag from my list of “BEST” people to share with. If in code, I wanted to make sure that Chirag was always added as a recipient, I would add him by id using the createPerson method from the platform:
// Create an interactive post builder.
PlusShare.Builder builder = new PlusShare.Builder(this, plusClient);
builder.addCallToAction(LABEL_VIEW_ITEM, callToActionUrl, callToActionDeepLinkId)
.setContentUrl(Uri.parse(getString(R.string.plus_example_deep_link_url)))
.setContentDeepLinkId(getString(R.string.plus_example_deep_link_id),
null, null, null)
.setText(mEditSendText.getText().toString());
if (best){
// Use the recipients list created from people.list...best
<strong> mBestRecipients.add(PlusShare.createPerson("118051310819094153327","Chirag Shah"));</strong>
builder.setRecipients(mBestRecipients);
}
In the above code snippet, you can see how I have created the recipient, Chirag Shah in this case, without using the list of people and instead directly adding by ID and display name. In practice, this is a more common use case and would probably be done using your own database of users.
Speaking of, I also would have liked to have had a longer discussion on who to target posts to. For example, you could look at the PhotoHunt app that we ship as part of the Google+ platform documentation. In this sample, we create an internal social graph of users within the app to people they know on Google+ who have installed the app. For that app, we could target interactive posts to the people who the current user has in their Circles on Google+ and who have already installed the app.
Another note on the code I showed on the gist, the best practice for Android would be to pre-load the list of people when the activity loads as opposed to waiting until the user clicks. That way, the UI doesn’t lag in cases where there is no internet connectivity. Because I wanted to show the before and after code and lazily copied the code from the ListPeopleActivity, I didn’t end up doing this.
A HUGE point that we didn’t cover was how the targeted posts appear across all platforms. When you specify a specific person, they will get notifications across all of the places that the notifications appear:
- Search
- GMail
- Google+
- Mobile
- and so on
As such, these targeted interactive posts are much more effective at reaching the people listed in the post.
Hope you enjoyed the GDL, it was fun to demo! Here’s a snapshot of Chirag and me during the session:
In the April 9th, 2013 Google+ Developers Live, Chirag and I demonstrated how to set the recipients for an Interactive Post in Android. You can watch the video below:
Code from the show
I have added a gist to GitHub for the code showing how I targeted Android interactive shares by combining the listPeopleActivity into the ShareActivity. The following snippets cover the relevant code changes relative to the Android quickstart sample:
Adding the PlusClient.OnPeopleLoadedListenter interface, for the asynchronous method from loadPeople:
public class ShareActivity extends FragmentActivity implements View.OnClickListener,
OnSignedInListener,
PlusClient.OnPeopleLoadedListener
{
A few variables for holding the PlusClient, used for getting the Interactive Share intent, and the ArrayList of people, populated in the onPeopleLoaded callback.
// Add lists for holding the people from people.list
private ArrayList<Person> mBestRecipients;
private PlusClient mPlusClient;
The onPeopleLoaded asynchronous callback implementation:
// The onPeopleLoaded method for the callback handling the response when the visible
// people are listed
@Override
public void onPeopleLoaded(ConnectionResult status, PersonBuffer personBuffer,
String nextPageToken) {
if (status.getErrorCode() == ConnectionResult.SUCCESS) {
mBestRecipients.clear();
try {
int count = personBuffer.getCount();
for (int i = 0; i < count; i++) {
Person toAdd = personBuffer.get(i).freeze();
mBestRecipients.add(toAdd);
}
} finally {
personBuffer.close();
}
} else {
Log.e(TAG, "Error when listing people: " + status);
}
Intent intent = getInteractivePostIntent(mPlusClient);
startActivityForResult(intent, REQUEST_CODE_INTERACTIVE_POST);
}
The code for adding the recipients to the post:
if (best){
// Use the recipients list created from people.list...best
builder.setRecipients(mBestRecipients);
}
Additional Notes, Errata
There were a few topics that we would have liked to cover in the episode but just didn’t have enough time for, ended up getting glossed over, or might have been lost when we had recorded live.
While I was setting up the APIs console, I mentioned putting in a meaningful name for the project name. What I should have indicated was to use an appropriate brand name for your company and an appropriate name for this particular client ID. When you are setting up the project, you want to make sure to get this right because it can be difficult to change it later on.
I really would have liked to show adding specific users by name. For example, I was missing Chirag from my list of “BEST” people to share with. If in code, I wanted to make sure that Chirag was always added as a recipient, I would add him by id using the createPerson method from the platform:
// Create an interactive post builder.
PlusShare.Builder builder = new PlusShare.Builder(this, plusClient);
builder.addCallToAction(LABEL_VIEW_ITEM, callToActionUrl, callToActionDeepLinkId)
.setContentUrl(Uri.parse(getString(R.string.plus_example_deep_link_url)))
.setContentDeepLinkId(getString(R.string.plus_example_deep_link_id),
null, null, null)
.setText(mEditSendText.getText().toString());
if (best){
// Use the recipients list created from people.list...best
<strong> mBestRecipients.add(PlusShare.createPerson("118051310819094153327","Chirag Shah"));</strong>
builder.setRecipients(mBestRecipients);
}
In the above code snippet, you can see how I have created the recipient, Chirag Shah in this case, without using the list of people and instead directly adding by ID and display name. In practice, this is a more common use case and would probably be done using your own database of users.
Speaking of, I also would have liked to have had a longer discussion on who to target posts to. For example, you could look at the PhotoHunt app that we ship as part of the Google+ platform documentation. In this sample, we create an internal social graph of users within the app to people they know on Google+ who have installed the app. For that app, we could target interactive posts to the people who the current user has in their Circles on Google+ and who have already installed the app.
Another note on the code I showed on the gist, the best practice for Android would be to pre-load the list of people when the activity loads as opposed to waiting until the user clicks. That way, the UI doesn’t lag in cases where there is no internet connectivity. Because I wanted to show the before and after code and lazily copied the code from the ListPeopleActivity, I didn’t end up doing this.
A HUGE point that we didn’t cover was how the targeted posts appear across all platforms. When you specify a specific person, they will get notifications across all of the places that the notifications appear:
- Search
- GMail
- Google+
- Mobile
- and so on
As such, these targeted interactive posts are much more effective at reaching the people listed in the post.
Hope you enjoyed the GDL, it was fun to demo! Here’s a snapshot of Chirag and me during the session:
best practices Google Google+ JavaScript Plus programming: google oauth PHP programming sign-in
by gguuss
leave a comment
Credential recovery: Reconnecting Google+ if something goes wrong
In my last post, I discussed tricks for upgrading tokens and upgrading to the Google+ sign-in button. This spurred some discussion on the Google+ post, most notably the question, “When do we get the refresh token?” In turn, I figured it would be a good time to write up a post on recovering the refresh token and explaining how and when you can get it. Let’s start with how you get offline access through the refresh token.
Getting offline credentials – the refresh token
How about some background on offline credentials! As described in the basics of OAuth documentation and elaborated in my blog post on the One-time-Code flow with the Google+ sign-in button, there are two types of tokens:
- The access token, which expires in 1 hour (3600 seconds for you “seconds since the UNIX Epoch” folks).
- The refresh token, which never expires, but can only be used to get access tokens – not to make API calls.
Again, the refresh token can not be used for performing API calls but only can be used to mint an access token for API access. This is useful on the server-side of your web sites because you don’t need to have your user signed in for operations like writing app activities. When performing client-side operations, you will never directly work with the refresh token because the Google client library will automatically refresh its access token.
In order to get a refresh token from the sign-in button, you must first create the markup for the button and include the data attribute, accesstype, set to offline:
<button
data-scope="https://www.googleapis.com/auth/plus.login"
data-requestvisibleactions="http://schemas.google.com/AddActivity"
data-clientId="YOUR_CLIENT_ID"
data-accesstype="offline"
data-callback="onSignInCallback"
data-theme="dark"
data-cookiepolicy="single_host_origin">
</button>
When the sign-in callback is returned after successful authorization, the argument passed to it will contain an authorization code. This code can then be exchanged for a refresh token and an access token. The Google+ quickstart samples all show how this is done in various languages. As an example, the following PHP code, from the PHP quickstart, shows how code exchange is performed:
$client = new Google_Client();
$client->setApplicationName(APPLICATION_NAME);
$client->setClientId(CLIENT_ID);
$client->setClientSecret(CLIENT_SECRET);
$client->setRedirectUri('postmessage');
$plus = new Google_PlusService($client);
...
// Exchange the OAuth 2.0 authorization code for user credentials.
$client->authenticate($code);
$token = json_decode($client->getAccessToken());
//verify the token
$reqUrl = 'https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=' .
$token->access_token;
$req = new Google_HttpRequest($reqUrl);
Note The refresh token will not always be returned from the code exchange. This is done because the JavaScript client does not need the refresh token. You’re probably wondering now, when do you get an access token…
When do you get a refresh token?
The simple answer is “Any time that the user is prompted to authorize your application, the authorization code can be exchanged for a refresh token.” The more complicated answer is… it depends. The reason for the complexity here is that the new Google+ sign-in button automatically signs the user in without prompting them because this is consistent with the user experience that Google wants for users across the web.
The following conditions are examples of what will cause the user to be prompted to authorize your application:
- The user has disconnected your application and then tries again to sign in
- The permissions that the app is requesting have changed
- You explicitly request the user to reauthorize*
*Note This should only be used in credential recovery scenarios, which will be discussed later in the article.
So there you have it, the authorization code can be exchanged to return a refresh token anytime the user sees this:
Now that you know when a user gets a new refresh token, you might wonder when you need to re-get that refresh token.
When do you need to recover credentials?
There are a number of scenarios for causes to need to recover server-stored credentials:
- The user disconnects your app
- The database gets corrupted
- An authorization code is exchanged and does not return a refresh token – this could happen if the user blocks your XHR somehow or errors at just the right moment, then signs in again.
So, let’s assume that the worst has happened and you have an invalid refresh token. When this happens, you will get an error from the API indicating that the authorization tokens are no longer valid. The following examples show how you can simulate these scenarios.
Example 1: The user disconnected the application but the session persisted
As an example of things going terribly wrong, manually disconnect the PHP starter I set up from a previous post by:
- Connecting the starter project demo
- Visiting your apps page on Google+ and disconnecting the application
Example 2: Ruining the stored credentials
For simplicity, I have added another couple of endpoints to the PHP server, the first endpoint will destroy the credentials in the user’s session:
- /ruin - destroy the user’s session
Now that you’ve created a state where the user credentials are bad, you can see that the data is bad by looking at the credentials as is now enabled through the following API calls I added to the server:
- /tokendump - Show the session token, if you ruined the session, this will be empty
- /tokeninfo - Test the access token in the session, if you ruined the session, this will show an error
- Try to perform the authorized request to list visible people - if you have ruined the session, this will return an error
Let’s take a look at the third approach, trying to list the people circled. After attempting the API call, you will see the following response:
Google_ServiceException: Error calling GET https://www.googleapis.com/plus/v1/people/me/people/visible: (401) Invalid Credentials
The 401 error, “invalid credentials”, indicates that something wrong has happened. In this case, the user’s account needs to be recovered and access tokens need to be regenerated.
If you were to perform a check against the tokeninfo endpoint for an invalid access token, you would see an error as follows:
{"error":"invalid_token","error_description":"Invalid Value"}
Finally, if the user disconnected their account and you checked a token against tokeninfo, you would see the same error:
{"error":"invalid_token","error_description":"Invalid Value"}
Let’s finish with a discussion of how you can recover the user’s credentials.
How do you recover the credentials?
So what do you do!??!! You now know that you need to regenerate the authorization credentials as indicated from a server-side call. If the user disconnected your account (Example 1 from the previous section), the answer is simple: the next time the user signs in, you exchange the authorization code for a refresh token, update your database, and are done. If the user does not sign-in again with your application, you should remove any stored data that must be removed as described in the Google+ Developer Platform policies.
So, let’s say the user hasn’t disconnected but their authorization data is no longer valid. In this more complicated case (Example 2), the user hasn’t disconnected from your application. If the user returns to the site’s main page, only an access token will be returned from the access code. To see this happen:
- /ruin - destroy the user’s session
- /signin.php - this will automatically authorize the user and the code returned will only return an access token
- /tokendump - Test the access token in the session, you can dump the user’s session using this script.
Note There is no refresh token! This is because the consent dialog was not displayed as described in “When do I get a refresh token”.
To address this scenario, you must force the consent dialog to appear so that the user is then prompted for allowing offline access to your application, and then you can exchange the returned authorization code for updated credentials. The following code shows how you can force the consent dialog to render for recovery scenarios:
<button class="g-signin"
data-scope="https://www.googleapis.com/auth/plus.login"
data-requestvisibleactions="http://schemas.google.com/AddActivity"
data-clientId="YOUR_CLIENT_ID"
data-accesstype="offline"
data-approvalprompt="force"
data-callback="onSignInCallback"
data-theme="dark"
data-cookiepolicy="single_host_origin">
</button>
The following demo recovers the user’s account.
This code, which runs server-side, first removes the invalid session credentials. Next, it forces the approval dialog to appear with the aforementioned markup. Finally, it exchanges the returned code for a new refresh/access token.
Conclusions
Be prepared for the worst and support account recovery on your sites for the rare case in which the credentials you have are bad. You should check that you are getting the refresh token when you expect it in order to make sure that you aren’t storing invalid credentials. If you wanted to be extra careful, you could occasionally audit your credentials database for accounts that have invalid refresh / access tokens for Google+.
In my last post, I discussed tricks for upgrading tokens and upgrading to the Google+ sign-in button. This spurred some discussion on the Google+ post, most notably the question, “When do we get the refresh token?” In turn, I figured it would be a good time to write up a post on recovering the refresh token and explaining how and when you can get it. Let’s start with how you get offline access through the refresh token.
Getting offline credentials – the refresh token
How about some background on offline credentials! As described in the basics of OAuth documentation and elaborated in my blog post on the One-time-Code flow with the Google+ sign-in button, there are two types of tokens:
- The access token, which expires in 1 hour (3600 seconds for you “seconds since the UNIX Epoch” folks).
- The refresh token, which never expires, but can only be used to get access tokens – not to make API calls.
Again, the refresh token can not be used for performing API calls but only can be used to mint an access token for API access. This is useful on the server-side of your web sites because you don’t need to have your user signed in for operations like writing app activities. When performing client-side operations, you will never directly work with the refresh token because the Google client library will automatically refresh its access token.
In order to get a refresh token from the sign-in button, you must first create the markup for the button and include the data attribute, accesstype, set to offline:
<button
data-scope="https://www.googleapis.com/auth/plus.login"
data-requestvisibleactions="http://schemas.google.com/AddActivity"
data-clientId="YOUR_CLIENT_ID"
data-accesstype="offline"
data-callback="onSignInCallback"
data-theme="dark"
data-cookiepolicy="single_host_origin">
</button>
When the sign-in callback is returned after successful authorization, the argument passed to it will contain an authorization code. This code can then be exchanged for a refresh token and an access token. The Google+ quickstart samples all show how this is done in various languages. As an example, the following PHP code, from the PHP quickstart, shows how code exchange is performed:
$client = new Google_Client();
$client->setApplicationName(APPLICATION_NAME);
$client->setClientId(CLIENT_ID);
$client->setClientSecret(CLIENT_SECRET);
$client->setRedirectUri('postmessage');
$plus = new Google_PlusService($client);
...
// Exchange the OAuth 2.0 authorization code for user credentials.
$client->authenticate($code);
$token = json_decode($client->getAccessToken());
//verify the token
$reqUrl = 'https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=' .
$token->access_token;
$req = new Google_HttpRequest($reqUrl);
Note The refresh token will not always be returned from the code exchange. This is done because the JavaScript client does not need the refresh token. You’re probably wondering now, when do you get an access token…
When do you get a refresh token?
The simple answer is “Any time that the user is prompted to authorize your application, the authorization code can be exchanged for a refresh token.” The more complicated answer is… it depends. The reason for the complexity here is that the new Google+ sign-in button automatically signs the user in without prompting them because this is consistent with the user experience that Google wants for users across the web.
The following conditions are examples of what will cause the user to be prompted to authorize your application:
- The user has disconnected your application and then tries again to sign in
- The permissions that the app is requesting have changed
- You explicitly request the user to reauthorize*
*Note This should only be used in credential recovery scenarios, which will be discussed later in the article.
So there you have it, the authorization code can be exchanged to return a refresh token anytime the user sees this:
Now that you know when a user gets a new refresh token, you might wonder when you need to re-get that refresh token.
When do you need to recover credentials?
There are a number of scenarios for causes to need to recover server-stored credentials:
- The user disconnects your app
- The database gets corrupted
- An authorization code is exchanged and does not return a refresh token – this could happen if the user blocks your XHR somehow or errors at just the right moment, then signs in again.
So, let’s assume that the worst has happened and you have an invalid refresh token. When this happens, you will get an error from the API indicating that the authorization tokens are no longer valid. The following examples show how you can simulate these scenarios.
Example 1: The user disconnected the application but the session persisted
As an example of things going terribly wrong, manually disconnect the PHP starter I set up from a previous post by:
- Connecting the starter project demo
- Visiting your apps page on Google+ and disconnecting the application
Example 2: Ruining the stored credentials
For simplicity, I have added another couple of endpoints to the PHP server, the first endpoint will destroy the credentials in the user’s session:
- /ruin - destroy the user’s session
Now that you’ve created a state where the user credentials are bad, you can see that the data is bad by looking at the credentials as is now enabled through the following API calls I added to the server:
- /tokendump - Show the session token, if you ruined the session, this will be empty
- /tokeninfo - Test the access token in the session, if you ruined the session, this will show an error
- Try to perform the authorized request to list visible people - if you have ruined the session, this will return an error
Let’s take a look at the third approach, trying to list the people circled. After attempting the API call, you will see the following response:
Google_ServiceException: Error calling GET https://www.googleapis.com/plus/v1/people/me/people/visible: (401) Invalid Credentials
The 401 error, “invalid credentials”, indicates that something wrong has happened. In this case, the user’s account needs to be recovered and access tokens need to be regenerated.
If you were to perform a check against the tokeninfo endpoint for an invalid access token, you would see an error as follows:
{"error":"invalid_token","error_description":"Invalid Value"}
Finally, if the user disconnected their account and you checked a token against tokeninfo, you would see the same error:
{"error":"invalid_token","error_description":"Invalid Value"}
Let’s finish with a discussion of how you can recover the user’s credentials.
How do you recover the credentials?
So what do you do!??!! You now know that you need to regenerate the authorization credentials as indicated from a server-side call. If the user disconnected your account (Example 1 from the previous section), the answer is simple: the next time the user signs in, you exchange the authorization code for a refresh token, update your database, and are done. If the user does not sign-in again with your application, you should remove any stored data that must be removed as described in the Google+ Developer Platform policies.
So, let’s say the user hasn’t disconnected but their authorization data is no longer valid. In this more complicated case (Example 2), the user hasn’t disconnected from your application. If the user returns to the site’s main page, only an access token will be returned from the access code. To see this happen:
- /ruin - destroy the user’s session
- /signin.php - this will automatically authorize the user and the code returned will only return an access token
- /tokendump - Test the access token in the session, you can dump the user’s session using this script.
Note There is no refresh token! This is because the consent dialog was not displayed as described in “When do I get a refresh token”.
To address this scenario, you must force the consent dialog to appear so that the user is then prompted for allowing offline access to your application, and then you can exchange the returned authorization code for updated credentials. The following code shows how you can force the consent dialog to render for recovery scenarios:
<button class="g-signin"
data-scope="https://www.googleapis.com/auth/plus.login"
data-requestvisibleactions="http://schemas.google.com/AddActivity"
data-clientId="YOUR_CLIENT_ID"
data-accesstype="offline"
data-approvalprompt="force"
data-callback="onSignInCallback"
data-theme="dark"
data-cookiepolicy="single_host_origin">
</button>
The following demo recovers the user’s account.
This code, which runs server-side, first removes the invalid session credentials. Next, it forces the approval dialog to appear with the aforementioned markup. Finally, it exchanges the returned code for a new refresh/access token.
Conclusions
Be prepared for the worst and support account recovery on your sites for the rare case in which the credentials you have are bad. You should check that you are getting the refresh token when you expect it in order to make sure that you aren’t storing invalid credentials. If you wanted to be extra careful, you could occasionally audit your credentials database for accounts that have invalid refresh / access tokens for Google+.
best practices demos Google Google+ hacks JavaScript php Plus programming: google hacks PHP programming tricks
by gguuss
1 comment
Google+ code tricks: Upgrading to the new sign-in / upgrading scopes
I have had many folks ask me how they can do the following things:
- Upgrade from the traditional OAuth flows to the new one-time-code flow
- Authorize with just plus.login and then add additional (optional but useful) services to the user’s account
These are great scenarios where developers and site owners can benefit from understanding the user experience and options that are available when moving forward with the new sign-in features of Google+. In this post, I’ll share some of my personal thoughts and experience with adding, changing, and upgrading OAuth v2 scopes with the sign-in button. Note These are preliminary thoughts on how this could be done and are not official guidance – please let me know if you have additional suggestions for ways that this could be done better!
Upgrade from OAuth v2 to sign-in
In this scenario, you have a site that works with the existing OAuth v2 flows, most likely a server-side flow. If you’re looking to upgrade to use the sign-in button flow, your existing users will need to reauthorize your application. This is because the the sign-in button implicitly is requesting the plus.login scope for sign-in. Let’s take a look at the experience for how this scenario would work!
A demo of the upgrade flow
First, look at this page:
Simple Server-side Sign-in Demo
If the page is not loading, you can logout here. After you connect your account, you will reach an authorization page such as the following:
When you reach the site again, signed in to Google, you will be authorized and the page will know your id and can render your profile.
Let’s now assume we want to upgrade the user’s account to use sign-in in order to add users from Google+ to it. In order to do this, the user must login again, this time using the sign-in button as shown in the following demo:
One-time-code Server-side Sign-in Demo
More on why the user must reauthorize later… but the dialog looks as follows
After authorizing again, the user’s account will then be upgraded to take advantage of the new Google+ Sign-in features.
Let’s now take a look at the steps used to upgrade your backend database to reflect the upgrade.
Updating the user information in the site’s data model
First, recall the simple example where the userinfo.email scope was requested and the user was authorized using the conventional server-side flow. At this point, your site could have a model for the user similar to the following:
Let’s assume that the user has created data associated with that flow, so the (…) could represent additional data specific to your site. Their account ID has been set, because it’s returned with the plus.email scope so the user’s account credentials already exist in this database on the site.
Next, after you have updated your site to have the new sign-in button and the user reauthorizes, you can update the existing data on your site for the user and can add the additional information returned from Google+. From a back-end perspective, the model could now look something like this:
The refresh token and access token, highlighted in red, are updated after the code-exchange happens server-side on the one-time-code flow. This is done because the new credentials have access to the additional scopes. The VisibleUser table is also populated with all of the users visible to the site so that the social graph can be taken advantage of.
Next, let’s take a look at the programming steps to upgrade your site.
Steps to upgrade the site
Let’s take a closer look at what was done to accomplish this upgrade path. First, the scopes on the API project must be updated to include the Google+ API. This is done by turning on the Google+ scope from the API console:
Next, the site needs to be updated to include the new sign-in button as described on the Google+ developers documentation page, Google+ sign-in. Summarized briefly, the markup code needs to be added to the site:
<button
data-scope="https://www.googleapis.com/auth/plus.login"
data-requestvisibleactions="http://schemas.google.com/AddActivity"
data-clientId="YOUR_CLIENT_ID"
data-accesstype="offline"
data-callback="onSignInCallback"
data-theme="dark"
data-cookiepolicy="single_host_origin">
</button>
…and a sign-in callback will need to be created that POSTs data to the server-side component:
/**
* Hides the sign-in button and connects the server-side app after
* the user successfully signs in.
*
* @param {Object} authResult An Object which contains the access token and
* other authentication information.
*/
onSignInCallback: function(authResult) {
$('#authResult').html('Auth Result:<br/>');
for (var field in authResult) {
$('#authResult').append(' ' + field + ': ' + authResult[field] + '<br/>');
}
if (authResult['access_token']) {
// The user is signed in
this.authResult = authResult;
// After we load the Google+ API, render the profile data from Google+.
gapi.client.load('plus','v1',this.renderProfile);
} else if (authResult['error']) {
// There was an error, which means the user is not signed in.
// As an example, you can troubleshoot by writing to the console:
console.log('There was an error: ' + authResult['error']);
$('#authResult').append('Logged out');
$('#authOps').hide('slow');
$('#gConnect').show();
}
console.log('authResult', authResult);
}
You can learn more about the one-time-code flow by starting with the Google+ PHP Quickstart, but I’ll go a little further here. In cases where the site already has a user, the account can be looked up by their Google ID, which was most likely an index used previously when getting the user credentials from the userinfo.email scope. By matching the ID to the one returned from the plus.login scope, the account has been determined to have been created before and the credentials can be updated for the authorization credentials to the Google authentication servers. Once you have identified the user to upgrade, the persisted refresh token and access token need to be replaced with the new ones.
What is happening behind the scenes is that the OAuth flow in the original site is requesting only the userinfo.email scope. In the updated site, the sign-in button is implicitly requesting the plus.login scope so the user must be prompted again for permissions. When the user authorizes again on the new site, the identifier for the user’s Google account stay the same, so the account can again easily be matched up to reflect the updated permissions.
Adding additional scopes to a user’s account
Related to the first example is when you want a user to sign up for a service without needing to grant full permissions to your application and then later needing to add additional, optional, scopes to the associated account. For example, let’s say that you have a service that uses Google+ for login and creating an account but then later you want to add access to a user’s Google Calendar and Google Drive. What you can do is create a configuration page that dynamically sets the scopes on the sign-in button and then renders the button to reauthorize the user as shown before.
Warning: This is a hack that works for now but is not necessarily a best practice, use at your own risk!
Scare text aside… let’s look at how this could work.
- The user signs up, you request only the scopes required for signing up / signing in on your site as seen in the original one-time-code sign-in demo.
- Later, you bring the user to a configuration page where they select various scopes and then dynamically add these scopes to an authorization request.
The following demo performs some tricks to programmatically add and change the scopes that are requested and then render the sign-in button programmatically:
Demo: Tricks and hacks for Google+ Sign-in authorization scopes
The (definitely not production, there are global variables!) code for dynamically changing the scopes is as follows:
var calendarScopeVar = '';
var driveScopeVar= '';
function toggleCalendar(){
if (calendarScopeVar == ''){
calendarScopeVar = ' https://www.googleapis.com/auth/calendar';
}else{
calendarScopeVar = '';
}
render();
}
function toggleDrive(){
if (driveScopeVar == ''){
driveScopeVar = ' https://www.googleapis.com/auth/drive';
}else{
driveScopeVar = '';
}
render();
}
</script>
Checkboxes are added that toggle the scopes:
<input type="checkbox" onClick="toggleCalendar()"></input>Toggle Calendar<br>
<input type="checkbox" onClick="toggleDrive()"></input>Toggle Drive<br>
<div id="outer">
<div id="gConnect">
<button id="customBtn"></button>
</div>
</div>
Every time that the checkboxes are changed, you re-render the sign-in button as shown in the following code.
function render() {
$('#gConnect').empty();
$('#gConnect').html('<button id="customBtn"></button>');
var scope = 'https://www.googleapis.com/auth/plus.login';
scope += ' https://www.googleapis.com/auth/userinfo.email';
scope += calendarScopeVar;
scope += driveScopeVar;
gapi.signin.render('customBtn', {
'callback': 'onSignInCallback',
'clientid': '{{ CLIENT_ID }}',
'cookiepolicy': 'single_host_origin',
'requestvisibleactions': 'http://schemas.google.com/AddActivity',
'scope':scope
});
}
When the user clicks sign-in, the scopes are requested and the user will be re-authorized. The following image shows the dialog that appears when you select all of the optional scopes.
Upon completion of the authorization request, you will again exchange the code server-side to get and update your authorization tokens. After the authorization code is exchanged, the credentials returned will be authorized to have the additional scopes for calendar and/or drive. Upon completion of the authorization flow, you should replace your existing credentials with the updated ones that now have the new authorization parameters set. Note be careful that you don’t remove the scopes that you have already requested and need – plus.login and userinfo.email in this example.
Additional resources
So there you have it, upgrading and replacing scopes using the Google+ sign-in button. This probably has gotten you thinking about how you can do this on your own sites and in your own experiments. The following links should help to get you going and might spark some creativity for you:
I have had many folks ask me how they can do the following things:
- Upgrade from the traditional OAuth flows to the new one-time-code flow
- Authorize with just plus.login and then add additional (optional but useful) services to the user’s account
These are great scenarios where developers and site owners can benefit from understanding the user experience and options that are available when moving forward with the new sign-in features of Google+. In this post, I’ll share some of my personal thoughts and experience with adding, changing, and upgrading OAuth v2 scopes with the sign-in button. Note These are preliminary thoughts on how this could be done and are not official guidance – please let me know if you have additional suggestions for ways that this could be done better!
Upgrade from OAuth v2 to sign-in
In this scenario, you have a site that works with the existing OAuth v2 flows, most likely a server-side flow. If you’re looking to upgrade to use the sign-in button flow, your existing users will need to reauthorize your application. This is because the the sign-in button implicitly is requesting the plus.login scope for sign-in. Let’s take a look at the experience for how this scenario would work!
A demo of the upgrade flow
First, look at this page:
Simple Server-side Sign-in Demo
If the page is not loading, you can logout here. After you connect your account, you will reach an authorization page such as the following:
When you reach the site again, signed in to Google, you will be authorized and the page will know your id and can render your profile.
Let’s now assume we want to upgrade the user’s account to use sign-in in order to add users from Google+ to it. In order to do this, the user must login again, this time using the sign-in button as shown in the following demo:
One-time-code Server-side Sign-in Demo
More on why the user must reauthorize later… but the dialog looks as follows
After authorizing again, the user’s account will then be upgraded to take advantage of the new Google+ Sign-in features.
Let’s now take a look at the steps used to upgrade your backend database to reflect the upgrade.
Updating the user information in the site’s data model
First, recall the simple example where the userinfo.email scope was requested and the user was authorized using the conventional server-side flow. At this point, your site could have a model for the user similar to the following:
Let’s assume that the user has created data associated with that flow, so the (…) could represent additional data specific to your site. Their account ID has been set, because it’s returned with the plus.email scope so the user’s account credentials already exist in this database on the site.
Next, after you have updated your site to have the new sign-in button and the user reauthorizes, you can update the existing data on your site for the user and can add the additional information returned from Google+. From a back-end perspective, the model could now look something like this:
The refresh token and access token, highlighted in red, are updated after the code-exchange happens server-side on the one-time-code flow. This is done because the new credentials have access to the additional scopes. The VisibleUser table is also populated with all of the users visible to the site so that the social graph can be taken advantage of.
Next, let’s take a look at the programming steps to upgrade your site.
Steps to upgrade the site
Let’s take a closer look at what was done to accomplish this upgrade path. First, the scopes on the API project must be updated to include the Google+ API. This is done by turning on the Google+ scope from the API console:
Next, the site needs to be updated to include the new sign-in button as described on the Google+ developers documentation page, Google+ sign-in. Summarized briefly, the markup code needs to be added to the site:
<button
data-scope="https://www.googleapis.com/auth/plus.login"
data-requestvisibleactions="http://schemas.google.com/AddActivity"
data-clientId="YOUR_CLIENT_ID"
data-accesstype="offline"
data-callback="onSignInCallback"
data-theme="dark"
data-cookiepolicy="single_host_origin">
</button>
…and a sign-in callback will need to be created that POSTs data to the server-side component:
/**
* Hides the sign-in button and connects the server-side app after
* the user successfully signs in.
*
* @param {Object} authResult An Object which contains the access token and
* other authentication information.
*/
onSignInCallback: function(authResult) {
$('#authResult').html('Auth Result:<br/>');
for (var field in authResult) {
$('#authResult').append(' ' + field + ': ' + authResult[field] + '<br/>');
}
if (authResult['access_token']) {
// The user is signed in
this.authResult = authResult;
// After we load the Google+ API, render the profile data from Google+.
gapi.client.load('plus','v1',this.renderProfile);
} else if (authResult['error']) {
// There was an error, which means the user is not signed in.
// As an example, you can troubleshoot by writing to the console:
console.log('There was an error: ' + authResult['error']);
$('#authResult').append('Logged out');
$('#authOps').hide('slow');
$('#gConnect').show();
}
console.log('authResult', authResult);
}
You can learn more about the one-time-code flow by starting with the Google+ PHP Quickstart, but I’ll go a little further here. In cases where the site already has a user, the account can be looked up by their Google ID, which was most likely an index used previously when getting the user credentials from the userinfo.email scope. By matching the ID to the one returned from the plus.login scope, the account has been determined to have been created before and the credentials can be updated for the authorization credentials to the Google authentication servers. Once you have identified the user to upgrade, the persisted refresh token and access token need to be replaced with the new ones.
What is happening behind the scenes is that the OAuth flow in the original site is requesting only the userinfo.email scope. In the updated site, the sign-in button is implicitly requesting the plus.login scope so the user must be prompted again for permissions. When the user authorizes again on the new site, the identifier for the user’s Google account stay the same, so the account can again easily be matched up to reflect the updated permissions.
Adding additional scopes to a user’s account
Related to the first example is when you want a user to sign up for a service without needing to grant full permissions to your application and then later needing to add additional, optional, scopes to the associated account. For example, let’s say that you have a service that uses Google+ for login and creating an account but then later you want to add access to a user’s Google Calendar and Google Drive. What you can do is create a configuration page that dynamically sets the scopes on the sign-in button and then renders the button to reauthorize the user as shown before.
Warning: This is a hack that works for now but is not necessarily a best practice, use at your own risk!
Scare text aside… let’s look at how this could work.
- The user signs up, you request only the scopes required for signing up / signing in on your site as seen in the original one-time-code sign-in demo.
- Later, you bring the user to a configuration page where they select various scopes and then dynamically add these scopes to an authorization request.
The following demo performs some tricks to programmatically add and change the scopes that are requested and then render the sign-in button programmatically:
Demo: Tricks and hacks for Google+ Sign-in authorization scopes
The (definitely not production, there are global variables!) code for dynamically changing the scopes is as follows:
var calendarScopeVar = '';
var driveScopeVar= '';
function toggleCalendar(){
if (calendarScopeVar == ''){
calendarScopeVar = ' https://www.googleapis.com/auth/calendar';
}else{
calendarScopeVar = '';
}
render();
}
function toggleDrive(){
if (driveScopeVar == ''){
driveScopeVar = ' https://www.googleapis.com/auth/drive';
}else{
driveScopeVar = '';
}
render();
}
</script>
Checkboxes are added that toggle the scopes:
<input type="checkbox" onClick="toggleCalendar()"></input>Toggle Calendar<br>
<input type="checkbox" onClick="toggleDrive()"></input>Toggle Drive<br>
<div id="outer">
<div id="gConnect">
<button id="customBtn"></button>
</div>
</div>
Every time that the checkboxes are changed, you re-render the sign-in button as shown in the following code.
function render() {
$('#gConnect').empty();
$('#gConnect').html('<button id="customBtn"></button>');
var scope = 'https://www.googleapis.com/auth/plus.login';
scope += ' https://www.googleapis.com/auth/userinfo.email';
scope += calendarScopeVar;
scope += driveScopeVar;
gapi.signin.render('customBtn', {
'callback': 'onSignInCallback',
'clientid': '{{ CLIENT_ID }}',
'cookiepolicy': 'single_host_origin',
'requestvisibleactions': 'http://schemas.google.com/AddActivity',
'scope':scope
});
}
When the user clicks sign-in, the scopes are requested and the user will be re-authorized. The following image shows the dialog that appears when you select all of the optional scopes.
Upon completion of the authorization request, you will again exchange the code server-side to get and update your authorization tokens. After the authorization code is exchanged, the credentials returned will be authorized to have the additional scopes for calendar and/or drive. Upon completion of the authorization flow, you should replace your existing credentials with the updated ones that now have the new authorization parameters set. Note be careful that you don’t remove the scopes that you have already requested and need – plus.login and userinfo.email in this example.
Additional resources
So there you have it, upgrading and replacing scopes using the Google+ sign-in button. This probably has gotten you thinking about how you can do this on your own sites and in your own experiments. The following links should help to get you going and might spark some creativity for you:
howtos Linux ruby Tools: command line linux programming ruby rvm shell unix
by gguuss
leave a comment
Random useful stuff
Every day I find things that are insanely nice to have or useful. These things vary from a blog post that saves me hours of abort/retry/fail to really handy utilities and fancy frameworks. It’s worth mentioning a few here.
Installing RVM on OS X
This blog post on installing RVM on OSX is very informative. The solution proposed at the end of the blog post was enough to get the XCode command line tools to install RVM. The issue with installations on OSX seems to be that their (special, one of a kind, non-standard, etc) compiler is quirky so you must trick it into being more compatible. The relevant line from the article is for the install command`:
rvm install <version> --reconfigure --debug -C --enable-pthread --with-gcc=clang
It’s actually probably worth mentioning that RVM is extremely handy. There’s nothing worse than having to sudo to install gems or try to manage different versions of Ruby on your machine. Ruby introduces tons of breaking changes with each release, so be careful of which version you are running, particularly if you just got a book for what you thought was the latest version.
Getting alt+drag support in Windows
I love various tweaks in the window managers that are available for Linux. One most notable feature is the ability to hold alt and drag windows. There’s a Google code project for Alt dragging behavior that lets me work with the fancy pants window dragging behavior of my favorite Linux window mangers.
Sinatra
The first time that I started learning Ruby development, I learned Rails. I should have started with Sinatra. This simple and concise web server is extremely easy to configure and map. The following is an example implementation of a web server implementing multiple RESTful endpoints and various web paths:
require 'sinatra'
someJson = <<-QQ
{
"glossary": {
"title": "example glossary",
"GlossDiv": {
"title": "S",
"GlossList": {
"GlossEntry": {
"ID": "SGML",
"SortAs": "SGML",
"GlossTerm": "Standard Generalized Markup Language",
"Acronym": "SGML",
"Abbrev": "ISO 8879:1986",
"GlossDef": {
"para": "A meta-markup language, used to create markup languages such as DocBook.",
"GlossSeeAlso": ["GML", "XML"]
},
"GlossSee": "markup"
}
}
}
}
}
QQ
get '/' do
"Look at me now, look at me now"
end
get '/gus' do
"I'm getting paper"
end
get '/gus.json' do
content_type :json
someJson
end
get '/afile' do
send afile
end
Yeah, that’s a web server. Not until using this library had I felt there was “nothing left to take away” from such frameworks.
Revisiting a few old friends on the Unix/Linux command line
scp – copy files over ssh. I always forget the colon on the remote server line. The following is an example of how I move in to a new machine.
scp ~/.bash_profile user@remoteserver:~/
scp ~/.bashrc user@remoteserver:~/
scp ~/.vimrc user@remoteserver:~/
rsync – copy file differences. This is amazingly handy when you need to copy large amounts of data over your network because when things go wrong, you can easily start off where you left off. Syntax is just like cp:
rsync -r ~/big_folder/ user@remoteserver:~/
ssh -X – tunnel X11 over SSH. I don’t use graphical programs remotely, but when I do, I tunnel over ssh. This is rarely useful because remotely running X is slow and miserable, but sometimes you just gotta and it’s nice to know.
ssh -X <remoteserver>
Odds and ends
But wait, there’s more! A few odds and ends:
- A JSON validator
- W3C checker - it does funky stuff with <p> tags though
- Creative commons image search on Flickr
- I love my MotoActv
- Dillinger markdown editor
- simpl.info concise code examples
That’s all, folks, thanks for reading
Please feel free to share if you have any newish favorite things you’ve found out about.
Every day I find things that are insanely nice to have or useful. These things vary from a blog post that saves me hours of abort/retry/fail to really handy utilities and fancy frameworks. It’s worth mentioning a few here.
Installing RVM on OS X
This blog post on installing RVM on OSX is very informative. The solution proposed at the end of the blog post was enough to get the XCode command line tools to install RVM. The issue with installations on OSX seems to be that their (special, one of a kind, non-standard, etc) compiler is quirky so you must trick it into being more compatible. The relevant line from the article is for the install command`:
rvm install <version> --reconfigure --debug -C --enable-pthread --with-gcc=clang
It’s actually probably worth mentioning that RVM is extremely handy. There’s nothing worse than having to sudo to install gems or try to manage different versions of Ruby on your machine. Ruby introduces tons of breaking changes with each release, so be careful of which version you are running, particularly if you just got a book for what you thought was the latest version.
Getting alt+drag support in Windows
I love various tweaks in the window managers that are available for Linux. One most notable feature is the ability to hold alt and drag windows. There’s a Google code project for Alt dragging behavior that lets me work with the fancy pants window dragging behavior of my favorite Linux window mangers.
Sinatra
The first time that I started learning Ruby development, I learned Rails. I should have started with Sinatra. This simple and concise web server is extremely easy to configure and map. The following is an example implementation of a web server implementing multiple RESTful endpoints and various web paths:
require 'sinatra'
someJson = <<-QQ
{
"glossary": {
"title": "example glossary",
"GlossDiv": {
"title": "S",
"GlossList": {
"GlossEntry": {
"ID": "SGML",
"SortAs": "SGML",
"GlossTerm": "Standard Generalized Markup Language",
"Acronym": "SGML",
"Abbrev": "ISO 8879:1986",
"GlossDef": {
"para": "A meta-markup language, used to create markup languages such as DocBook.",
"GlossSeeAlso": ["GML", "XML"]
},
"GlossSee": "markup"
}
}
}
}
}
QQ
get '/' do
"Look at me now, look at me now"
end
get '/gus' do
"I'm getting paper"
end
get '/gus.json' do
content_type :json
someJson
end
get '/afile' do
send afile
end
Yeah, that’s a web server. Not until using this library had I felt there was “nothing left to take away” from such frameworks.
Revisiting a few old friends on the Unix/Linux command line
scp – copy files over ssh. I always forget the colon on the remote server line. The following is an example of how I move in to a new machine.
scp ~/.bash_profile user@remoteserver:~/ scp ~/.bashrc user@remoteserver:~/ scp ~/.vimrc user@remoteserver:~/
rsync – copy file differences. This is amazingly handy when you need to copy large amounts of data over your network because when things go wrong, you can easily start off where you left off. Syntax is just like cp:
rsync -r ~/big_folder/ user@remoteserver:~/
ssh -X – tunnel X11 over SSH. I don’t use graphical programs remotely, but when I do, I tunnel over ssh. This is rarely useful because remotely running X is slow and miserable, but sometimes you just gotta and it’s nice to know.
ssh -X <remoteserver>
Odds and ends
But wait, there’s more! A few odds and ends:
- A JSON validator
- W3C checker - it does funky stuff with <p> tags though
- Creative commons image search on Flickr
- I love my MotoActv
- Dillinger markdown editor
- simpl.info concise code examples
That’s all, folks, thanks for reading
Please feel free to share if you have any newish favorite things you’ve found out about.
Google+ JavaScript Plus programming: best google javascript practices programming
by gguuss
leave a comment
A tale of two RESTful API queries…
At the suggestion of +Will Norris, I updated this demo code for translating URLs to activity IDs to now use a filter. The following code highlights the differences:
< + '/activities/public?fields=items%2Fid%2Citems%2Furl&key=' + key
---
> + '/activities/public?key=' + key
The only difference is the fields parameter that I had configured using the fields editor from the API explorer.
I didn’t realize how much less data would be used by the API calls but to illustrate the difference I created some screenshots.
An example of the activity feed from API calls without the filter:
An example of the activity feed from API calls with the filter:
Yeah, there’s a lot less data in the second screenshot, like 20x less data. Actually…
2.65 kb with the filter versus:
97.25 kb without the filter.
This is a difference of 36x. That’s crazy!
If you can’t see the images or want to see the differences for yourself, compare the console output from the unfiltered version of urltoid and the filtered version of urltoid in your browser.
The key thing to look at in the results is the difference between each of the items. The content after the line > 0 : Object is the relevant difference, in the first example without the filter there are dozens of fields being returned of varying size, in the second example, only two fields that are relatively small are returned. I have clearly been wasting lots of bandwidth by not filtering my API calls.
After seeing the differences, I will definitely start thinking about filtering specific fields from API calls, it’s easy to do and actually makes the API call output easier to debug. In the grander scheme of things, filtering will save end user’s CPU cycles and bandwidth. If you really wanted to stretch this idea out completely, this means that less power would be used globally, less heat generated by computers, and less fossil fuels consumed for power… wait, this could reduce global warming!
OK, I got a little carried away there… the moral of the story is this, filter your API calls whenever you can.
At the suggestion of +Will Norris, I updated this demo code for translating URLs to activity IDs to now use a filter. The following code highlights the differences:
< + '/activities/public?fields=items%2Fid%2Citems%2Furl&key=' + key --- > + '/activities/public?key=' + key
The only difference is the fields parameter that I had configured using the fields editor from the API explorer.
I didn’t realize how much less data would be used by the API calls but to illustrate the difference I created some screenshots.
An example of the activity feed from API calls without the filter:
An example of the activity feed from API calls with the filter:
Yeah, there’s a lot less data in the second screenshot, like 20x less data. Actually…
2.65 kb with the filter versus:
97.25 kb without the filter.
This is a difference of 36x. That’s crazy!
If you can’t see the images or want to see the differences for yourself, compare the console output from the unfiltered version of urltoid and the filtered version of urltoid in your browser.
The key thing to look at in the results is the difference between each of the items. The content after the line > 0 : Object is the relevant difference, in the first example without the filter there are dozens of fields being returned of varying size, in the second example, only two fields that are relatively small are returned. I have clearly been wasting lots of bandwidth by not filtering my API calls.
After seeing the differences, I will definitely start thinking about filtering specific fields from API calls, it’s easy to do and actually makes the API call output easier to debug. In the grander scheme of things, filtering will save end user’s CPU cycles and bandwidth. If you really wanted to stretch this idea out completely, this means that less power would be used globally, less heat generated by computers, and less fossil fuels consumed for power… wait, this could reduce global warming!
OK, I got a little carried away there… the moral of the story is this, filter your API calls whenever you can.
demos Google+ JavaScript samples Tools: google javascript plus programming
by gguuss
leave a comment
Getting an activity ID from a Google+ Post URL
Taking the URL to a post and then determining the post ID for additional API calls is a little tricky but also fundamental for the Google+ public data API. First, you have to list activities and then search through them to determine which is the actual activity that you’re searching for. To show you how to take a URL from Google+ and determine the activity ID, I have created a demo application that finds the ID for a post given the URL to the post on Google+. Let’s walk through the demo!
This demo is very minimal, all it does is:
- Parse the user ID from the URL.
- Search the activities for the given URL.
- Match an activity with the same canonical URL link as the post.
- Show the activity ID.
The following code parses the user ID from the URL:
function search(){
// url is in a text input element with id 'url'
var url = document.getElementById('url').value;
searchForUrl(url, 0, '');
}
function searchForUrl(searchUrl, queryCount, nextPageToken){
// https://plus.google.com/{userid}/.../.../
var userId = searchUrl.split('/')[3];
...
Note that should the URL change, the code too must be updated to reflect the new point for the userid. However, because the API is RESTful, this structure should be pretty stable.
The following code searches for activities:
...
// Set parameters for the query
var URL = 'https://www.googleapis.com/plus/v1/people/' + userId
+ '/activities/public?key=' + key
+ "&orderBy=recent&pageToken="+nextPageToken;
performXHR(URL, searchUrl, queryCount, nextPageToken);
}
// performXHR - used to trigger the XMLHttpRequest
function performXHR(URL, postUrl, nextPageToken){
var request = new XMLHttpRequest();
request['postUrl'] = postUrl;
request['nextPageToken'] = nextPageToken;
request.open('GET', URL, true);
request.send(); // because of "false" above, will block until the request is done
// and status is available. Not recommended, however it works for simple cases.
request.onreadystatechange = function(){
if (request.readyState == 4) {
var query = request['postUrl'];
var nextPageToken = request['nextpagetoken'];
var activities = JSON.parse(request.responseText).items;
nextPageToken = JSON.parse(request.responseText).nextPageToken;
for (value in activities){
console.log(value);
}
return handleActivities(activities, query, nextPageToken);
}
};
}
This code is a little more complicated. First, the activties/list RESTful API endpoint is formed using the userid from the previous step. Next, the XmlHttpRequest (XHR) is formed and sent. Finally, the results are parsed into a JSON object.
The following code traverses the activities and tries to match against the url values:
// handleActivities - Parses and stores activities from the XMLHttpRequest
function handleActivities(activities, postUrl, queryCount, nextPageToken){
for (var activity in activities){
activity = activities[activity];
if (activity['url'] == postUrl){
targetActivity = activity;
document.getElementById('result').value= 'ID is:\n' + activity.id;
isFound = true;
}
}
if (queryCount < maxQueryCount && !isFound){
queryCount++;
// throttle calls using timer to avoid reaching query limit
setTimeout(searchForUrl(postUrl, queryCount, nextPageToken), 100);
}
}
This code just walks through the returned activities and then checks if any of the activities references the URL being searched for. If the URL is found, the result is displayed,. IF the URL is not yet found, additional queries are performed, passing the next page token to go deeper into the user’s activities.
The following code is the relevant part from the previous step that shows the id:
if (activity['url'] == postUrl){
targetActivity = activity;
document.getElementById('result').value= 'ID is:\n' + activity.id;
isFound = true;
}
Please feel free to ask any questions you have in the comments or on the Google+ link used to +1 / share the post.
Taking the URL to a post and then determining the post ID for additional API calls is a little tricky but also fundamental for the Google+ public data API. First, you have to list activities and then search through them to determine which is the actual activity that you’re searching for. To show you how to take a URL from Google+ and determine the activity ID, I have created a demo application that finds the ID for a post given the URL to the post on Google+. Let’s walk through the demo!
This demo is very minimal, all it does is:
- Parse the user ID from the URL.
- Search the activities for the given URL.
- Match an activity with the same canonical URL link as the post.
- Show the activity ID.
The following code parses the user ID from the URL:
function search(){
// url is in a text input element with id 'url'
var url = document.getElementById('url').value;
searchForUrl(url, 0, '');
}
function searchForUrl(searchUrl, queryCount, nextPageToken){
// https://plus.google.com/{userid}/.../.../
var userId = searchUrl.split('/')[3];
...
Note that should the URL change, the code too must be updated to reflect the new point for the userid. However, because the API is RESTful, this structure should be pretty stable.
The following code searches for activities:
...
// Set parameters for the query
var URL = 'https://www.googleapis.com/plus/v1/people/' + userId
+ '/activities/public?key=' + key
+ "&orderBy=recent&pageToken="+nextPageToken;
performXHR(URL, searchUrl, queryCount, nextPageToken);
}
// performXHR - used to trigger the XMLHttpRequest
function performXHR(URL, postUrl, nextPageToken){
var request = new XMLHttpRequest();
request['postUrl'] = postUrl;
request['nextPageToken'] = nextPageToken;
request.open('GET', URL, true);
request.send(); // because of "false" above, will block until the request is done
// and status is available. Not recommended, however it works for simple cases.
request.onreadystatechange = function(){
if (request.readyState == 4) {
var query = request['postUrl'];
var nextPageToken = request['nextpagetoken'];
var activities = JSON.parse(request.responseText).items;
nextPageToken = JSON.parse(request.responseText).nextPageToken;
for (value in activities){
console.log(value);
}
return handleActivities(activities, query, nextPageToken);
}
};
}
This code is a little more complicated. First, the activties/list RESTful API endpoint is formed using the userid from the previous step. Next, the XmlHttpRequest (XHR) is formed and sent. Finally, the results are parsed into a JSON object.
The following code traverses the activities and tries to match against the url values:
// handleActivities - Parses and stores activities from the XMLHttpRequest
function handleActivities(activities, postUrl, queryCount, nextPageToken){
for (var activity in activities){
activity = activities[activity];
if (activity['url'] == postUrl){
targetActivity = activity;
document.getElementById('result').value= 'ID is:\n' + activity.id;
isFound = true;
}
}
if (queryCount < maxQueryCount && !isFound){
queryCount++;
// throttle calls using timer to avoid reaching query limit
setTimeout(searchForUrl(postUrl, queryCount, nextPageToken), 100);
}
}
This code just walks through the returned activities and then checks if any of the activities references the URL being searched for. If the URL is found, the result is displayed,. IF the URL is not yet found, additional queries are performed, passing the next page token to go deeper into the user’s activities.
The following code is the relevant part from the previous step that shows the id:
if (activity['url'] == postUrl){
targetActivity = activity;
document.getElementById('result').value= 'ID is:\n' + activity.id;
isFound = true;
}
Please feel free to ask any questions you have in the comments or on the Google+ link used to +1 / share the post.
CSharp programming Windows XAML: .NET C# google GPlus metro programming windows programming windows store apps
by gguuss
4 comments
Pulling Google+ data into Windows Store apps
If you caught the last GDL show for Google+, I demoed a few things I have been working on, most notably my Google+ demo for Windows 8. The following screenshot shows the app running within the Windows 8 Simulator:
As you can see, it’s a basic Windows Store app and just integrates a simple layout with the GridView control. I’ll give you a brief overview of how the app works and how you could get started with our APIs in Microsoft’s new app model. This post will be focused on getting the relevant Google+ Data using the REST API.
The sample that was created for this code is available from here:
Please note that this is an early version of the sample, various best practices are not being followed but updates to the sources should address these in the future.
Authentication
A key concept demonstrated in this example is authentication. Because the most exciting Google+ APIs from the perspective of Windows Store apps require that you be granted permissions by the user, you will probably be most interested in this step. Let’s go over how authentication will work for this app.
Authentication overview
This app is using the installed application flow so the following steps will be performed for authentication and API calls:
- Authenticate the user to get a single use access code
- Exchange the access code for a refresh token
- Use the refresh token to get an access token
- Use the access token to perform API calls
Some of the steps are made much easier because of new APIs for Windows Store apps. However, I had trouble using the .NET client library because some of the referenced classes were deprecated for the new app model. I’ll be looking into what can be done to make the service generator build compatible libraries.
Without further adieu, let’s talk about data, starting with authentication!
Performing Authentication
The following code shows the code for the first OAUTH flow step, prompting the user for their credentials to get an access code:
public async void Auth()
{
Windows.Storage.ApplicationData.Current.LocalSettings.Values["code"] = "";
if (access_token == null)
{
if (refreshToken == null && code == null)
{
try
{
String GoogleURL = "https://accounts.google.com/o/oauth2/auth?client_id=" + Uri.EscapeDataString(clientID) + "&redirect_uri=" + Uri.EscapeDataString(callbackUrl) + "&response_type=code&scope=" + Uri.EscapeDataString(scope);
System.Uri StartUri = new Uri(GoogleURL);
// When using the desktop flow, the success code is displayed in the html title of this end uri
System.Uri EndUri = new Uri("https://accounts.google.com/o/oauth2/approval?");
DebugPrint("Navigating to: " + GoogleURL);
WebAuthenticationResult WebAuthenticationResult = await WebAuthenticationBroker.AuthenticateAsync(
WebAuthenticationOptions.UseTitle,
StartUri,
EndUri);
if (WebAuthenticationResult.ResponseStatus == WebAuthenticationStatus.Success)
{
string response = WebAuthenticationResult.ResponseData.ToString();
// strip to start of auth code
code = response.Substring(response.IndexOf("=") + 1);
Windows.Storage.ApplicationData.Current.LocalSettings.Values["code"] = code;
// TODO: switch off button, enable writes, etc.
}
else if (WebAuthenticationResult.ResponseStatus == WebAuthenticationStatus.ErrorHttp)
{
//TODO: handle WebAuthenticationResult.ResponseErrorDetail.ToString()
}
else
{
// This could be a response status of 400 / 401
// Could be really useful to print debugging information such as "Your applicationID is probably wrong"
//TODO: handle WebAuthenticationResult.ResponseStatus.ToString()
}
}
catch (Exception Error)
{
//
// Bad Parameter, SSL/TLS Errors and Network Unavailable errors are to be handled here.
//
DebugPrint(Error.ToString());
}
}
}
codeToAcccesTok();
}
What is going on in this code snippet is the WebAuthenticationBroker is used to perform the basic OAUTH flow. The result of this flow is a “code” value. This code is a single use code that can be exchanged for a refresh token and an access token. Now that we have the code, it’s time to exchange that code for an access token and a refresh token. The following code snippet shows how that’s done using a HTTP Post method and the HttpClient class:
private async void codeToAcccesTok()
{
string oauthUrl = "https://accounts.google.com/o/oauth2/token";
HttpClient theAuthClient = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, oauthUrl);
// default case, we have an authentication code, want a refresh/access token
string content = "code=" + code + "&" +
"client_id=" + clientID + "&" +
"client_secret=" + clientSecret + "&" +
"redirect_uri=" + callbackUrl + "&" +
"grant_type=authorization_code";
if (refreshToken != null)
{
content = "refresh_token=" + refreshToken + "&" +
"client_id=" + clientID + "&" +
"client_secret=" + clientSecret + "&" +
"grant_type=refresh_token";
}
request.Method = HttpMethod.Post;
request.Content = new StreamContent(new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(content)));
request.Content.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
try
{
HttpResponseMessage response = await theAuthClient.SendAsync(request);
parseAccessToken(response);
}
catch (HttpRequestException hre)
{
}
}
In the above code snippet, we setup an HTTP POST request and then send it to the Google authorization server with the parameters we need for authentication. The response data from the call contains a parameter for the access token as well as a refresh token. The following code snippet shows how the access token and refresh token are parsed from the response.
private async void codeToAcccesTok()
{
string oauthUrl = "https://accounts.google.com/o/oauth2/token";
HttpClient theAuthClient = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, oauthUrl);
// default case, we have an authentication code, want a refresh/access token
string content = "code=" + code + "&" +
"client_id=" + clientID + "&" +
"client_secret=" + clientSecret + "&" +
"redirect_uri=" + callbackUrl + "&" +
"grant_type=authorization_code";
if (refreshToken != null)
{
content = "refresh_token=" + refreshToken + "&" +
"client_id=" + clientID + "&" +
"client_secret=" + clientSecret + "&" +
"grant_type=refresh_token";
}
request.Method = HttpMethod.Post;
request.Content = new StreamContent(new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(content)));
request.Content.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
try
{
HttpResponseMessage response = await theAuthClient.SendAsync(request);
parseAccessToken(response);
}
catch (HttpRequestException hre)
{
}
}
public async void parseAccessToken(HttpResponseMessage response)
{
string content = await response.Content.ReadAsStringAsync();
if (content != null)
{
string[] lines = content.Replace("\"", "").Replace(" ","").Replace(",","").Split('\n');
for (int i = 0; i < lines.Length; i++)
{
string[] paramSplit = lines[i].Split(':');
if (paramSplit[0].Equals("access_token")){
access_token = paramSplit[1];
}
if (paramSplit[0].Equals("refresh_token")){
refreshToken = paramSplit[1];
Windows.Storage.ApplicationData.Current.LocalSettings.Values["refreshToken"] = refreshToken;
}
}
if (access_token != null)
{
getProfile();
}
else
{
// something is wrong, fix this
}
}
}
In the above code, the parameters are extracted from the response data and parsed with a few simple string split calls. The refresh token is stored for later and the access token is cached for API calls. Because the parameters used for exchanging an access code for an access token/refresh token are very similar to those used when exchanging a refresh token for an access token, this method is reused later to get access tokens from the refresh token.
At this point, you have used the access code to get a refresh token and access token. Now you’re ready to make authenticated API calls to Google+.
Performing authenticated API calls to Google+
In order to perform authenticated API calls to Google+, you need first to have gotten an access token. This was done in the previous steps and is cached within the application. Next, you will make the API call using a HttpClient. Finally, you will be serializing the objects from JSON. The first step we’ll discuss is specifying objects to be used later for JSON serialization.
Specifying objects for JSON serialization
Before you can parse JSON data from API responses, you need to specify the objects that will be parsed from the API call responses returned over REST. You can generate these classes from the discovery document. Because this was just an exploration of Metro and a demo, I hand crafted a few of the classes as opposed to writing a generator. The following example is the ActorClass and it’s child classes, which are returned within the activity feed and the people APIs.
[System.Runtime.Serialization.DataContractAttribute()]
public partial class NameClass
{
[System.Runtime.Serialization.DataMemberAttribute()]
public string familyName {get; set;}
[System.Runtime.Serialization.DataMemberAttribute()]
public string givenName { get; set; }
}
[System.Runtime.Serialization.DataContractAttribute()]
public partial class ImageClass
{
[System.Runtime.Serialization.DataMemberAttribute()]
public string url { get; set; }
}
[System.Runtime.Serialization.DataContractAttribute()]
public partial class ActorClass
{
[System.Runtime.Serialization.DataMemberAttribute()]
public string id { get; set; }
[System.Runtime.Serialization.DataMemberAttribute()]
public string displayName { get; set; }
[System.Runtime.Serialization.DataMemberAttribute()]
public string nickname { get; set; }
[System.Runtime.Serialization.DataMemberAttribute()]
public string tagline { get; set; }
[System.Runtime.Serialization.DataMemberAttribute()]
public NameClass name { get; set; }
[System.Runtime.Serialization.DataMemberAttribute()]
public string url { get; set; }
[System.Runtime.Serialization.DataMemberAttribute()]
public ImageClass image { get; set; }
}
The classes and interfaces are specified using a shorthand that is common in C#/.NET for data contracts. Now that we have our objects for serialization, we’re ready to get the profile data and then serialize it to the actual objects.
Getting the user’s profile data
Here’s our favorite authenticated Google+ API call, getting profile data! First, we’ll need to specify the template that will be used by the JSON parser for storing the user’s profile object. This was described briefly in the above section.
Next, we’ll perform the RESTful query using the HttpClient.
public async void getProfile()
{
httpClient = new HttpClient();
var searchUrl = "https://www.googleapis.com/plus/v1/people/me/";
httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + access_token);
try
{
HttpResponseMessage response = await httpClient.GetAsync(searchUrl);
ParseProfile(response);
}
catch (HttpRequestException hre)
{
DebugPrint(hre.Message);
}
}
Finally, parse the profile into the object we specified earlier.
private async void ParseProfile(HttpResponseMessage response)
{
string content = await response.Content.ReadAsStringAsync();
if (content != null)
{
var serializer = new DataContractJsonSerializer(typeof(ActorClass));
thisUser = serializer.ReadObject(new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(content))) as ActorClass;
((MainPage)renderArea).RenderUser();
GetActivities();
}
}
You’ll now have an object, ActorClass, that has been populated with the information of the currently authenticated user. If you want to inspect the object, put a breakpoint into the application and see what’s in there. The following screenshot shows this in my project:
You can see the profile information for me in the object. This can be used later to render personalized data for the signed-in user. In my app’s case, the code behind just sets up the XAML objects based on the Actor object.
Conclusions
It’s really not that hard to run the REST flows from Windows Store apps. I think a logical next step for developers working on Windows 8 with Google+ is to implement a share contract because that would be really useful for users. Let me know if you have any questions about the sample! I’ll try and document the rest of how things work and how the UX works, but no guarantees because this is lower priority for me for now.
Finally, for y’all in the U.S., happy Thanksgiving! I hope you’re having a great time with your family and friends.
See Also
If you caught the last GDL show for Google+, I demoed a few things I have been working on, most notably my Google+ demo for Windows 8. The following screenshot shows the app running within the Windows 8 Simulator:
As you can see, it’s a basic Windows Store app and just integrates a simple layout with the GridView control. I’ll give you a brief overview of how the app works and how you could get started with our APIs in Microsoft’s new app model. This post will be focused on getting the relevant Google+ Data using the REST API.
The sample that was created for this code is available from here:
Please note that this is an early version of the sample, various best practices are not being followed but updates to the sources should address these in the future.
Authentication
A key concept demonstrated in this example is authentication. Because the most exciting Google+ APIs from the perspective of Windows Store apps require that you be granted permissions by the user, you will probably be most interested in this step. Let’s go over how authentication will work for this app.
Authentication overview
This app is using the installed application flow so the following steps will be performed for authentication and API calls:
- Authenticate the user to get a single use access code
- Exchange the access code for a refresh token
- Use the refresh token to get an access token
- Use the access token to perform API calls
Some of the steps are made much easier because of new APIs for Windows Store apps. However, I had trouble using the .NET client library because some of the referenced classes were deprecated for the new app model. I’ll be looking into what can be done to make the service generator build compatible libraries.
Without further adieu, let’s talk about data, starting with authentication!
Performing Authentication
The following code shows the code for the first OAUTH flow step, prompting the user for their credentials to get an access code:
public async void Auth()
{
Windows.Storage.ApplicationData.Current.LocalSettings.Values["code"] = "";
if (access_token == null)
{
if (refreshToken == null && code == null)
{
try
{
String GoogleURL = "https://accounts.google.com/o/oauth2/auth?client_id=" + Uri.EscapeDataString(clientID) + "&redirect_uri=" + Uri.EscapeDataString(callbackUrl) + "&response_type=code&scope=" + Uri.EscapeDataString(scope);
System.Uri StartUri = new Uri(GoogleURL);
// When using the desktop flow, the success code is displayed in the html title of this end uri
System.Uri EndUri = new Uri("https://accounts.google.com/o/oauth2/approval?");
DebugPrint("Navigating to: " + GoogleURL);
WebAuthenticationResult WebAuthenticationResult = await WebAuthenticationBroker.AuthenticateAsync(
WebAuthenticationOptions.UseTitle,
StartUri,
EndUri);
if (WebAuthenticationResult.ResponseStatus == WebAuthenticationStatus.Success)
{
string response = WebAuthenticationResult.ResponseData.ToString();
// strip to start of auth code
code = response.Substring(response.IndexOf("=") + 1);
Windows.Storage.ApplicationData.Current.LocalSettings.Values["code"] = code;
// TODO: switch off button, enable writes, etc.
}
else if (WebAuthenticationResult.ResponseStatus == WebAuthenticationStatus.ErrorHttp)
{
//TODO: handle WebAuthenticationResult.ResponseErrorDetail.ToString()
}
else
{
// This could be a response status of 400 / 401
// Could be really useful to print debugging information such as "Your applicationID is probably wrong"
//TODO: handle WebAuthenticationResult.ResponseStatus.ToString()
}
}
catch (Exception Error)
{
//
// Bad Parameter, SSL/TLS Errors and Network Unavailable errors are to be handled here.
//
DebugPrint(Error.ToString());
}
}
}
codeToAcccesTok();
}
What is going on in this code snippet is the WebAuthenticationBroker is used to perform the basic OAUTH flow. The result of this flow is a “code” value. This code is a single use code that can be exchanged for a refresh token and an access token. Now that we have the code, it’s time to exchange that code for an access token and a refresh token. The following code snippet shows how that’s done using a HTTP Post method and the HttpClient class:
private async void codeToAcccesTok()
{
string oauthUrl = "https://accounts.google.com/o/oauth2/token";
HttpClient theAuthClient = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, oauthUrl);
// default case, we have an authentication code, want a refresh/access token
string content = "code=" + code + "&" +
"client_id=" + clientID + "&" +
"client_secret=" + clientSecret + "&" +
"redirect_uri=" + callbackUrl + "&" +
"grant_type=authorization_code";
if (refreshToken != null)
{
content = "refresh_token=" + refreshToken + "&" +
"client_id=" + clientID + "&" +
"client_secret=" + clientSecret + "&" +
"grant_type=refresh_token";
}
request.Method = HttpMethod.Post;
request.Content = new StreamContent(new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(content)));
request.Content.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
try
{
HttpResponseMessage response = await theAuthClient.SendAsync(request);
parseAccessToken(response);
}
catch (HttpRequestException hre)
{
}
}
In the above code snippet, we setup an HTTP POST request and then send it to the Google authorization server with the parameters we need for authentication. The response data from the call contains a parameter for the access token as well as a refresh token. The following code snippet shows how the access token and refresh token are parsed from the response.
private async void codeToAcccesTok()
{
string oauthUrl = "https://accounts.google.com/o/oauth2/token";
HttpClient theAuthClient = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, oauthUrl);
// default case, we have an authentication code, want a refresh/access token
string content = "code=" + code + "&" +
"client_id=" + clientID + "&" +
"client_secret=" + clientSecret + "&" +
"redirect_uri=" + callbackUrl + "&" +
"grant_type=authorization_code";
if (refreshToken != null)
{
content = "refresh_token=" + refreshToken + "&" +
"client_id=" + clientID + "&" +
"client_secret=" + clientSecret + "&" +
"grant_type=refresh_token";
}
request.Method = HttpMethod.Post;
request.Content = new StreamContent(new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(content)));
request.Content.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
try
{
HttpResponseMessage response = await theAuthClient.SendAsync(request);
parseAccessToken(response);
}
catch (HttpRequestException hre)
{
}
}
public async void parseAccessToken(HttpResponseMessage response)
{
string content = await response.Content.ReadAsStringAsync();
if (content != null)
{
string[] lines = content.Replace("\"", "").Replace(" ","").Replace(",","").Split('\n');
for (int i = 0; i < lines.Length; i++)
{
string[] paramSplit = lines[i].Split(':');
if (paramSplit[0].Equals("access_token")){
access_token = paramSplit[1];
}
if (paramSplit[0].Equals("refresh_token")){
refreshToken = paramSplit[1];
Windows.Storage.ApplicationData.Current.LocalSettings.Values["refreshToken"] = refreshToken;
}
}
if (access_token != null)
{
getProfile();
}
else
{
// something is wrong, fix this
}
}
}
In the above code, the parameters are extracted from the response data and parsed with a few simple string split calls. The refresh token is stored for later and the access token is cached for API calls. Because the parameters used for exchanging an access code for an access token/refresh token are very similar to those used when exchanging a refresh token for an access token, this method is reused later to get access tokens from the refresh token.
At this point, you have used the access code to get a refresh token and access token. Now you’re ready to make authenticated API calls to Google+.
Performing authenticated API calls to Google+
In order to perform authenticated API calls to Google+, you need first to have gotten an access token. This was done in the previous steps and is cached within the application. Next, you will make the API call using a HttpClient. Finally, you will be serializing the objects from JSON. The first step we’ll discuss is specifying objects to be used later for JSON serialization.
Specifying objects for JSON serialization
Before you can parse JSON data from API responses, you need to specify the objects that will be parsed from the API call responses returned over REST. You can generate these classes from the discovery document. Because this was just an exploration of Metro and a demo, I hand crafted a few of the classes as opposed to writing a generator. The following example is the ActorClass and it’s child classes, which are returned within the activity feed and the people APIs.
[System.Runtime.Serialization.DataContractAttribute()]
public partial class NameClass
{
[System.Runtime.Serialization.DataMemberAttribute()]
public string familyName {get; set;}
[System.Runtime.Serialization.DataMemberAttribute()]
public string givenName { get; set; }
}
[System.Runtime.Serialization.DataContractAttribute()]
public partial class ImageClass
{
[System.Runtime.Serialization.DataMemberAttribute()]
public string url { get; set; }
}
[System.Runtime.Serialization.DataContractAttribute()]
public partial class ActorClass
{
[System.Runtime.Serialization.DataMemberAttribute()]
public string id { get; set; }
[System.Runtime.Serialization.DataMemberAttribute()]
public string displayName { get; set; }
[System.Runtime.Serialization.DataMemberAttribute()]
public string nickname { get; set; }
[System.Runtime.Serialization.DataMemberAttribute()]
public string tagline { get; set; }
[System.Runtime.Serialization.DataMemberAttribute()]
public NameClass name { get; set; }
[System.Runtime.Serialization.DataMemberAttribute()]
public string url { get; set; }
[System.Runtime.Serialization.DataMemberAttribute()]
public ImageClass image { get; set; }
}
The classes and interfaces are specified using a shorthand that is common in C#/.NET for data contracts. Now that we have our objects for serialization, we’re ready to get the profile data and then serialize it to the actual objects.
Getting the user’s profile data
Here’s our favorite authenticated Google+ API call, getting profile data! First, we’ll need to specify the template that will be used by the JSON parser for storing the user’s profile object. This was described briefly in the above section.
Next, we’ll perform the RESTful query using the HttpClient.
public async void getProfile()
{
httpClient = new HttpClient();
var searchUrl = "https://www.googleapis.com/plus/v1/people/me/";
httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + access_token);
try
{
HttpResponseMessage response = await httpClient.GetAsync(searchUrl);
ParseProfile(response);
}
catch (HttpRequestException hre)
{
DebugPrint(hre.Message);
}
}
Finally, parse the profile into the object we specified earlier.
private async void ParseProfile(HttpResponseMessage response)
{
string content = await response.Content.ReadAsStringAsync();
if (content != null)
{
var serializer = new DataContractJsonSerializer(typeof(ActorClass));
thisUser = serializer.ReadObject(new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(content))) as ActorClass;
((MainPage)renderArea).RenderUser();
GetActivities();
}
}
You’ll now have an object, ActorClass, that has been populated with the information of the currently authenticated user. If you want to inspect the object, put a breakpoint into the application and see what’s in there. The following screenshot shows this in my project:
You can see the profile information for me in the object. This can be used later to render personalized data for the signed-in user. In my app’s case, the code behind just sets up the XAML objects based on the Actor object.
Conclusions
It’s really not that hard to run the REST flows from Windows Store apps. I think a logical next step for developers working on Windows 8 with Google+ is to implement a share contract because that would be really useful for users. Let me know if you have any questions about the sample! I’ll try and document the rest of how things work and how the UX works, but no guarantees because this is lower priority for me for now.
Finally, for y’all in the U.S., happy Thanksgiving! I hope you’re having a great time with your family and friends.
See Also
Gus Class's portfolio
Social Media Links
Recent Posts
- Google+ Sign-In best practices
- Sharing: Best practices for targeting Interactive Posts
- Passive Sharing: Writing app activities without target URLs
- Making the most of the Google+ developer site
- Manipulating sites using the DOM editor in Chrome
- Even more common errors with Sign-in
- Google API clients: Why you should use them and how
- Developing in C# from OS X using MonoDevelop
- Targeting Interactive Post recipients in Android
- Credential recovery: Reconnecting Google+ if something goes wrong
Linkroll
Help I'm trapped in a code factory!
Short programming tutorials and random geek stuff.Tags
- .NET android C# canvas code coding css debugging demos development google google plus gotchas hacking hacks hangouts history html javascript markup oauth PHP plus programming REST robots schema.org sign-in windows XAML
Categories
- android
- best practices
- books
- C++
- canvas
- cracking
- CSharp
- CSS
- Customizing
- debugging
- demos
- development
- DirectX
- gadgets
- Google+
- gotchas
- gusstuff
- Hacking
- hacks
- hangouts
- hardware
- history
- howtos
- HTML
- java
- JavaScript
- Linux
- Mac
- music
- patterns
- Perl
- php
- Plus
- productivity
- programming
- python
- robots
- ruby
- samples
- Schema.org
- Tools
- Uncategorized
- videos
- Windows
- WordPress






















