Centralizing Access Token Requests

The current method to get an access token for an our APIs is to make a POST request containing a client ID and client secret to an API by appending “/token” to the end of the URL. For example, the first URL makes an access token request, and the second url makes an API request to the locations API:
  • POST https://api.oregonstate.edu/v1/locations/token
  • GET https://api.oregonstate.edu/v1/locations
Today, we are announcing the OAuth2 API, which performs OAuth2 related requests and serves as a centralized OAuth2 API. Developers can use the OAuth2 API to request an access token.
  • POST https://api.oregonstate.edu/oauth2/token
The token endpoint for the OAuth2 API allows access token requests for any API. Developers can then use the same access token in the Authorization header of their API request like normal.

Deprecation

Today, we are also deprecating the decentralized “/token” endpoints for our APIs. We plan to remove token endpoints from our APIs on Monday, November 13th 2017. We encourage you to start using the OAuth2 API instead for access token requests. Before the production change on November 13th, we’ll be removing the decentralized token endpoints from our APIs in our development environment on October 30th 2017. 
After Monday, November 13th, 2017, you won’t be able to get an access token by adding “/token” to the end of a request URL. For example, these requests won’t work after that day:
  • POST https://api.oregonstate.edu/v1/directory/token
  • POST https://api.oregonstate.edu/v1/locations/token
Instead, please use the OAuth2 API to get an access token. Link to documentation. 

OAuth2

Oregon State University uses OAuth 2 for API authentication and authorization. When someone registers an application on our developer portal, they get a client ID and client secret which are used during the API request process. To access an API resource, the client ID and secret are used in a token request to the OAuth2 API: POST https://api.oregonstate.edu/oauth2/token

The response for a token request will include an access token, which is used to get access to an API and has a limited lifetime. The response will also include a token expiration time and a list of APIs the access token may be used with. A developer can then use the access token in the header of a request to access an API the token is authorized for. This process works well for public data (like the locations or directory APIs) or when only specific people/departments can use an API.

Three-legged OAuth

Deprecating our decentralized token endpoints from our APIs allows us to direct all access token requests to one API instead of each individual one. This makes things simpler, but also allows us to expand our scope of OAuth2 to more than access token requests. One of the components of OAuth is the three-legged flow which allows an end-user to grant an application permission to access certain data about the user. For example, think about how applications on the web share data with each other. Let’s say a developer created a web form and allows a user to auto-fill information from their Facebook profile. The web form directs the user to Facebook to authorize the web form application to access the user’s data. This is an example of three-legged OAuth.

Enabling three-legged OAuth allows us to expand our scope when developing APIs to deal with more confidential or sensitive data, and lets the users decide on whether an application should access data about them. As an example, think about an API that could retrieve a student’s grades. The developer or the student (user in this example) shouldn’t have access to everyone’s grades. They should only be able to access their own. A student would log in (authenticate) before deciding if the application is allowed to retrieve their grades.

For more information on the OAuth standard, go to https://oauth.net/2/

Register an application on the developer portal to get started using some of OSU’s APIs: https://developer.oregonstate.edu

I’ve been working at Enterprise Computing Services at Oregon State University as a student developer for one year. In our group, we mainly focused on developing Application Programing Interface (API) and other relevant jobs. As a Computer Science major graduate student, real-world working experience gave me a very good opportunity to apply my academic knowledge and concepts to practical situations. Since there are various tools involved in software development, a student developer should learn and be able to use these tools very quickly.

Last summer, I worked on a big project which utilized two open source tools, Ansible and Jenkins, to automate our APIs’ deployment process and implement the concept of continuous integration. Because of this project, I got a chance to demo and present my work in front of lots of audiences including stakeholders. Being able to state the concept clearly to audiences is also a very important skill as a professional software developer. From my experience, these areas are important to any student who wants to become a professional developer.

  • Always practice and enhance your coding skill. Pick one or two programming languages you are familiar the most and keep practicing them. If possible, you can also choose some frameworks (e.g. Django or Flask) to implement your own project. Push them to GitHub so that people can easily view your technical skills and enthusiasm.
  • Writing skill is also important. As time goes by, it is easy to forget details of a project you worked on. Therefore, being able to write clear explanations of a project with well-documented documentation can help you and your teammates save a lot of time.
  • Time management. Manage your time wisely especially when you are a student and also a software developer at the same time. Scheduling your tasks by priorities is always a good idea and it helps you finish your tasks on time and efficiently.
  • Finally, good communication is the most critical skill you definitely need to have. From regular group meetings to large meetings across the departments, you will have many opportunities to demo your work or convince other people. Having a strong communication skill will absolutely help you and your team a lot.

In a nutshell, developing your technical skills and soft skills are equivalently important for a professional software developer. Student or whoever is able to show the above abilities will definitely be a good software developer. Remember that opportunity favors the prepared mind. Hope all future student developers can find a great journey here!

For the past year and a half, I’ve been working in two teams in Information Services at OSU as a student developer. My first year in SIG (Shared Infrastructure Group) gave me an opportunity to work on the open source CoprHD project and regularly collaborate with the community members and the developers from the industry. As the team leader, besides the work assigned to me, I was also responsible for tracking the progress of my team members, assuring the on-time delivery of the features. Giving presentations of our work based on different purposes to the audience from various backgrounds was another important part of this project.

My role in the second team was one of the developers in the team. This team involved more diverse tasks allowing me to grasp many skills in a short period. Similar to the previous work, presentations were also frequent activities. Team members share knowledge through demoing or explaining the work to the team members. On the other hand, I went through several interviews for the past year, which gave me a sense of desired skills in the industry. If I look back to the experiences of interview processes and my job, there are some tips I could share with the students who want to be developers, and some of which I wish I could have done better.

Communication Skills

I know this might sound cliche, but it is one of the most highly effective skills that can help you reach your goal whether to get the work done or the help you need. Specifically, being able to ask questions wisely will bring you the answer you need, reduce avoidable mistakes or get out of the tar pits. In addition, communication over emails is another routine. A clear and concise email not only shows your professionality but also leads up to prompt replies.

Moreover, as described above, presentations are commonplace at work, so being capable of showing your work through the presentations is not just desirable but also necessary. During interviews, it’s very likely to be asked to introduce the projects you have done, while at work it’s even more frequent to demonstrate your work/ideas to your team or even a larger audience. Therefore, capable of delivering your thoughts clearly or even vividly will be a big plus in the job market.

Technical Skills

Technical skills are your core competencies, and it’s very critical to keep strengthening the skills you already have. Further, being able to learn new skills and learn them quickly on demand might be even more valuable. It is very common that you are not familiar some of the techniques used in your project, which can be a programming language, a framework or a tool. Being able to grasp the knowledge and applying them to the project is also a demonstration of your ability to work.

Another suggestion is to be aware of your thought process and try to identify and form the most efficient one for yourself. The thought process, such as how you learn things, how you debug and how you figure out a problem will change over time along with your experience. And an awareness of the changes will help you improve your efficiency, which is also helpful for your interviews since a lot of interviewers will try to identify your thought process from the way you answer their questions.

Additionally, putting down the notes for the work you have done is one of the things that I wish I could have done better. No matter how confident you thought you would remember the work, after leaving it aside for couple months or even weeks, everything will look completely new to you.

In a nutshell, technical skills and the communication skills are the way to becoming a professional developer. I believe if one could continue enhancing the skills discussed above and be able to show them to the employers, he/she will be a strong hire in the job market.

I’ve been working in IT at OSU as a student for the past 3 years, but more recently, I’ve been taking more of the responsibilities of a developer over the course of this year. Growing into the role as a student developer with my job has been well-timed with my degree in Business Information Systems. My undergraduate studies this past academic year as a senior has involved more software architecture and development leading up to my graduation. The similarities between the work I’ve done for my job and for my degree have been complimentary, allowing me to share skills and techniques between the two disciplines.
Taking classes in a business environment has given me a different prospective on software development for my work. Information systems business classes, besides teaching programming, focused on making sure the outcome of software development is successful and addresses the needs of stakeholders. We were taught to focus on the problem trying to be solved, conceptualize a solution in a non-technical way to stakeholders, and develop measures of success to ensure the outcome isn’t a failure. These skills along with my experience as a developer guide some of the advice I have for students who want to be developers:
  • Be able to communicate non-technically when needed. Whether it be a supervisor, customer, or colleague in a different department. Being in a software development role means taking on the work that requires special skills and knowledge unique to you and your team. The ability to propose a better solution to a problem, explain an issue to a stakeholder, or even describing the work being done to someone who isn’t as technically proficient is key. I’ve always believed that being able to teach a topic or skill is a marker of proficiency in that area, and when it comes to software development and IT, being able to communicate something non-technically is a similar marker of proficiency. 
  • Remember the importance of soft skills like verbal communication, demo/presentation skills, and writing skills. According a survey conducting by Technical Councils of North America 70% of employers say soft skills are equally important as technical skills for success in a software development career. My experience in IT and software development has taught me the importance of these soft skills. It has always been beneficial for me to keep up with these skills through practice, whether it’s giving a demo at work or a presentation for a class.
  • Learn and practice technical skills through projects and practical experience. Learning technical skills is very important, but I would advise aspiring developers to practice and maintain their skills through methods that are demonstrable to employers. Being able to show a coding project or talk about projects accomplished during a job or internship might be required during the interview or application process. The knowledge of development skills serves as a foundation, but being able to demonstrate those skills is important for pursuing a career as a developer.
At the end of the day, good technical skills will be at the core of software development. However, getting in to software development as a career can be difficult without much prior experience. I believe demonstrating the skills above can show employers that someone is able to grow into a developer position to further diversify their technical and soft skills.

The ERP system that we use is Banner. There are some big architectural changes that we’ve been adopting. This translates into some changes on how we do development. We will try to summarize them in this post.

Revision Control

We were using SVN to manage code that our vendor provided. The code is now provided via git repositories! This meant that we needed to store these git repositories locally. Other units within Information Services in the past used GitLab ( https://about.gitlab.com ) . GitLab is a good open source solution, but our previous experience with it showed us that the monthly updated usually broke some aspect of functionality and the upgrades were painful due to rails / ruby version updates. We went with GitHub Enterprise ( https://enterprise.github.com/home ) . 

We talked to another couple of schools that used GitHub Enterprise (for other types of development) and they were very happy with the UI and maintenance. Our experience with upgrades to GitHub enterprise have been painless. Features and changes to the GitHub platform first appear in public github.com and after a couple of months we’ll see them come to an upgrade in GitHub Enterprise. 

The change of svn to git is not an easy change for our developers. The change from a centralized server such as svn where we mostly used TortoiseSVN as a client to a decentralized system such as git is a big change. We tried using Code School to provide devs with access to great git tutorials. The issue was that due to work related commitments and devs not actively using git, the training wasn’t effective. Our next plan of action is to have group git exercises in a frequent basis. This will expose developers to using git more frequently and use the new scm features that a decentralized system such as git provides. For GUI clients we recommend using SourceTree ( https://www.sourcetreeapp.com ) and within Linux we use the command line since that’s easier.

Development Environment

Our developers use Windows for development. When we started to experiment with Banner XE development, we ran into roadblocks. Having to manage different versions of Java or Grails in Windows is not easy. In *nix environments, we have tools such as SDKMAN ( http://sdkman.io ) to manage the versions of JVM tools. It took us days to get Grails applications and their dependencies properly running in Windows. That’s when we realized that Windows could work, but trying to replicate this setup in each developer workstation was going to be a nightmare. 

To make lives easier we used VirtualBox ( https://www.virtualbox.org ) and created a VM using Ubuntu. In this VM, we setup the various Java and Grails dependencies to build Grails Banner applications. By having a single VM, we could setup the dependencies and configure the JVM tools once and all the developers could leverage a single installation. We had a Google doc that specified how to setup and configure the dependencies. It was several pages long and mostly due to screenshots in Windows. On the other hand, the Linux instructions were much shorter and could be scripted.

Using VMs was great, but we started to run into some memory problems. Our development machines were about 4-5 years old with 16GB of RAM and non-ssd hard drives. The grails applications that we are dealing with easily require 3-4GB of RAM each. We also use Intellij IDEA Ultimate within VirtualBox. We found that Intellij IDEA worked properly within VirtualBox. To be on the safe side, we give a total of 6G of ram to VirtualBox. This meant that developers couldn’t run many applications in their machines. Web browsers use a lot of memory and trying to run two VirtualBox VMs concurrently wasn’t possible.

To support development, developers got new machines. The new workstations have 32G of ram and an SSD. A new CPU and GPU were also part of the upgrade, but we didn’t find them to be a constraint with the previous machines. The SSD provided some improvements for Windows, but once VirtualBox is running the SSD doesn’t make a huge difference. I would still recommend to others to upgrade to a new SSD and RAM if possible. It is a very cheap upgrade and you will run out of RAM.

Automation

In order to support the updated development workflow, we are using Jenkins ( https://jenkins.io/index.html ). The ESM tool provided by our ERP vendor leverages Jenkins as the underlying technology. From talking to our DBA, ESM only provides us with admin level access so it’s not something that we could easily allow devs to use, yet. We do have ESM installed, and our DBA uses it to fetch code from the vendor.

Since we have non grails based development it made sense for us to stand up a separate instance of Jenkins. We are leveraging Ansible ( https://www.ansible.com ) to setup the Jenkins, its dependencies and jobs. By using Ansible, we are able to test changes to Jenkins locally via Vagrant ( https://www.vagrantup.com ) in our workstations. We can go from a bare VM to start compiling an XE Grails application (using a jenkins job) within 5 – 7 minutes. 

Dev Practices - Ansible Automation

Workflow

So far we haven’t made any custom changes to the codebase. 

  1. A Jenkins job checks daily if a new git repository is available from the ERP vendor. If there is a new one, we create a new repo in github enterprise
  2. Daily we update our GitHub Enterprise repos with any new commits, branches and tags from the vendor

Dev Practices - Vendor Code Upates

The development workflow that we plan to use is the following:

  1. Use three git branches that mirror our instances for each application. One environment is production and the other two are development / test.
  2. When a developer wants to make a change to either the development or test environment, they would create a feature branch. The feature branch’s name is a ticket-id (from our bug tracker) and two / three word description of the change. This allows us to track a change / back to a developer and why the change is being made.
  3. We want to commit early and often to the feature branches. Once the code is ready, we’ll use GitHub’s Pull Requests to do reviews. 
  4. Jenkins jobs can be leveraged to perform checks on the code.
  5. Once the code is ready to be deployed to either the test or dev environment, a Jenkins job will generate a war file for our DBA.
  6. Our DBA then uses ant scripts provided by our ERP vendor to deploy the WAR file to Tomcat.

Dev Practices - Developer Workflow

The advantages of using Jenkins to compile the code is that we make sure there are no local code changes or dependencies in a developer’s workstations needed to compile code and not present in GitHub Enterprise. All war files are compiled in the same manner (JVM version, dependencies, etc). Naming of artifacts is consistent and Jenkins can send notifications when builds fail. Developers can review previous builds, generate new war files, and examine failed builds.

Next Steps

Some of our next steps and improvement areas:

  • Right now we are using Google docs to document steps for developers. These need to be improved since at the time we were heavily using Windows for development.
  • If you are coming from SVN, moving to git is a big change. We plan to do git exercises as a team on a weekly basis. This will help get our developers familiar with git commands, merging, branches and dealing with git conflicts.
  • As we start to make changes to the vendor supplied code, we need to figure out what version of a grails application we are running. We need to keep track not just of the vendor’s base version, but our commits / changes. We’ll use jenkins to name war files in a way that includes the environment, vendor version and our local commit sha1.
  • Containers are the next major step for virtualization. We plan to explore how we can best run WAR file in containers for development purposes.

Ever had an hour to kill on campus and been looking for an interesting class to drop in on? Look no further. Introducing… Classy.

CS372 is meeting *right* now in Kelley Engineering Center.

Classy is a simple web app which shows you a random, currently-happening class every time you load the page. We built Classy to demonstrate the class search API that we’ve been building. All the data it needs—the list of class subjects, the current term, and most importantly all the class data—is fetched via API calls in convenient JSON format, avoiding the need to scrape any data from the catalog.

Almost all of the data in the web catalog is available, including the meeting times for the class and enrollment numbers—the only notable exception being the course description. Classy leverages some of this extra catalog data to filter out classes which are very small and non-lecture classes (it would be kind of rude to walk into a 10-person recitation, after all).

There are still a couple areas where Classy could use improvements; for example, it doesn’t understand that summer classes only run for a few weeks of the term, or that group midterms don’t happen every week.

The source code for Classy is up on Github, and as soon as the class search API is made public through the developer portal, you’ll be able play with it yourself.

Posted in API.

One of the most commonly requested public API by students has been a class/catalog API. The fact that there’s no API for class/catalog data hasn’t stopped eager student developers. They usually end up scraping data from the catalog and storing it in a database where their applications can easily access it. We are happy to say that we have started work on a solution to this common student developer problem 🙂

The API will allow developers to query classes by term, subject and course number to retrieve full class information including details, teacher, class availability and other information publicly available via the course catalog. We have started our design process in github: https://github.com/osu-mist/courses-api-design using the OpenAPI Initiative format (formerly known as Swagger). You can use the swagger editor links below to see the first draft of the design:

Let us know what you think either with a comment or pull request. This design and the first implementation of this API won’t be final. Our goal is to release a beta version of the API, and collect developer feedback.

 

Posted in API.

When the Hackathon rolled around our team wanted to bring a project that extended or utilized our current CMS for a new purpose. We wanted something that we could start and finish in a single day and we also wanted a project that would take advantage of a team with diverse skill sets.

Enter bennyslista classified advertisements website exclusive to the Oregon State community with sections devoted to buying and selling textbooks, electronics, bikes and just about anything students need. Students can create and respond to listings through the site, making it a safe, secure place to buy and sell.” taken directly from our about page.

Screen Shot 2016-05-18 at 2.15.46 PM

Bennyslist is a group within the main.oregonstate.edu drupal site. We decided to use our CMS because it allows us to tie into existing university themes and branding but it also gives us quick access to some powerful components.

CAS Authentication

Really at the core of the concept is that bennyslist is private to the OSU community. Craigslist fails because of the constant bombardment of spam and phishing attempts. Just try to sell anything and you will see for yourself, it can be an aggravating experience. Because OSU Drupal already has an authentication tool built into it we were easily able to specify which components would be “gated” via ONID login.

If you want to see what is available or want to post something for sale yourself then you will be required to use your OSU issued account. This was also nice because it did not add yet another account credential to store, memorize or update.

Webform

The second component that we used was Drupal Webforms. Our audience can go to the form and fill out what they have for sale and once submitted those entries are dynamically display in our listings. This allows them to come back and edit the posts and also means that it is fully automated. No staff time is required in moving submissions onto the for sale/trade list. However, it also provides a way for administrators to remove postings that are deemed unacceptable.

Screen Shot 2016-05-18 at 2.32.10 PM

Because of these components it was an easy decision to go with a centrally hosted CMS as opposed to trying to create our own home grown application. There are certainly some compromises to make, but in the end we were able to create a fully automated and functional tool.

The rest of the work went into marketing and communications. We had designers create attractive images, a writer help with copywriting and a video producer even had time to create a commercial for the tool. Taking a fully integrated approach to our product allowed us to deliver a completed product in the time allowed.

So go ahead and give it a try, think about how you use Drupal and OSU templates. They do have some limitations but that doesn’t mean you can’t explore different functionality and strategy for your sites.

The Team

  • Callie Newton – Web Editor and Writer
  • Oliver Day – Interactive Designer
  • Santiago Uceda – Assistant Director (Illustrator for this project)
  • Darryl Lai – Multimedia Producer
  • Kegan Sims – Drupal Architect

I run two email newsletters for the Graduate School. One delivered weekly through MailChimp and one monthly through lists.oregonstate.edu. The monthly newsletter is also posted to our Drupal website. I spend a lot of time on these newsletters and what follows is how I write and proof them. I also use these methods for copy editing blog posts and other types of editing and writing (minus the CSS inlining.) At the end, I’ll share some additional tools that I hope to incorporate in the future.

Write in Markdown

For me, the easiest way to write my newsletters is in Markdown. While Markdown is not an exact standard, there are enough services using it that it is fairly well supported across the web and within tools. Github supports it. BeeGit is a content writing and editing platform that uses it.

I use the Sublime Text 3 text editor with the Markdown Editing package. The Markdown Editing package gives you some special highlighting, a color scheme, and other niceties. It does not, however, provide an HTML preview. When first writing in Markdown, I used BeeGit for its preview and Markdown cheat sheet until I became more comfortable with the syntax.

Why do I use Markdown? My top reasons:

  • Conversion to HTML with Pandoc (more on this later)
  • I can use my text editor (goodbye Word)
  • The files are only plain text for maximum preservation value
  • Creating a link is a breeze
  • Creating a link is a breeze
  • Creating a link is a breeze

So yeah, creating links is a breeze. My newsletters take the format of blurb and link, blurb and link, etc. If I had to create each link using a WYSIWYG, I would find a new line of work.

Words to avoid, grammar and style

Some talented people have released tools that check your text for common errors beyond spelling mistakes. I use four of these.

Proselint focuses on usage, not grammar. Here’s a list of what it checks for. It is a command-line only tool at this time.

retext-mapbox-standard is a combination of language tools that checks for gendered language and potential slurs, words to avoid in educational writing, jargon, and more, plus it can read Markdown. The project is meant as an example of what organizations can do to enforce their own style guides, but I use it as provided by Mapbox. Also a command-line tool.

OSU copy cop is a tool I made that checks some of the editorial standards set forth by OSU. Saying “I made” isn’t really true: I copied it from the original Copy cop and added a few OSU things.

Grammerly is a web and desktop application that checks usage, grammar, spelling, and more. Available as a free tier and paid tier. I copy my text into it and out of it, which isn’t efficient, but gets the job done and it doesn’t complain about the Markdown I paste in. The available browser plugin also checks your text while you write posts on websites like Facebook and Twitter, which can help you avoid some embarrassing mistakes.

Pandoc to convert to HTML

Pandoc is a fantastic tool that converts between file types. Converting Markdown to HTML goes like this:

pandoc -o file-out.html file-in.md

That’s it and bam! HTML ready to go.

Add CSS to the header

For my monthly email newsletter I like to inline some of my CSS into the HTML, so before sending it through an inliner tool (see below) I have pandoc create a standalone HTML document with my CSS in the HEAD of that doc. If you give Pandoc the -H option it will grab the contents of that file and put it in the HEAD of the doc you are creating.

pandoc -o -s file-out.html file-in.md -H add-to-head.html

The add-to-head.html file looks like:

<style>
  p {
    margin-bottom: 1em;
  }
</style>

Inline the CSS

Now that my HTML doc is ready with the styles in the HEAD, I can run the whole thing through an inliner tool and it will put the styles inline with my HTML. I use Mailchimp’s inliner tool for this. I think there are some command line tools for this (like Juice) but this website makes it quick.

Add to Drupal and send email

Finally, after the inliner step, my newsletter’s HTML is ready. I go to my Drupal site and paste in the HTML. From there I copy the text and paste it directly into Gmail for sending. The result is a plain, single column newsletter layout. Here’s an example.

Future improvements

I’d like to add a HTML template system (like this or this) to my workflow so I can create better layouts for the email newsletters. For that, I’ll need to go back to an email program that allows me to edit the HTML directly, like Thunderbird, or use an email service provider. For Mailchimp, WordPress, or anywhere else I just need HTML, I follow the steps above but stop after I convert the Markdown to HTML.

— John McQueen, Web Communications, Oregon State University Graduate School

The OSU Developer Portal (https://developer.oregonstate.edu) currently has two APIs available, Directory (for people) and Location (for campus locations). This post describes my experience developing a “hello world” framework with the Location API. I got excellent reuse of the framework code when also experimenting with the Directory API.

I logged on to the OSU Developer Portal, registered a new app, and got the Consumer Key and Consumer Secret strings that are required to make calls to the API.

A Consumer Key looks something like m5l2jS54r7XqkkvJVovdpUY1o4DMl0la and a Consumer Secret like koMYj5HVd9m963a8. Not the actual ones! Get yer own!

Calling an OSU API has two steps:

  1. An HTTP POST to the getAccessToken method, with Consumer Key and Consumer Secret, to get an access token.
  2. An HTTP GET to to the desired API method, here getLocations, with the access token obtained above and any optional parameters, here a q query string.

For example, calling getLocations with the query q=kerr returns this JSON:

{
“links”:{
“self”:”https://api.oregonstate.edu/v1/locations?q=kerr&page[number]=1&page[size]=10″,
“first”:”https://api.oregonstate.edu/v1/locations?q=kerr&page[number]=1&page[size]=10″,
“last”:”https://api.oregonstate.edu/v1/locations?q=kerr&page[number]=1&page[size]=10″,
“prev”:null,
“next”:null
},
“data”:[
{
“id”:”2e9ee2d06066654f61a178560c2c137a”,
“type”:”locations”,
“attributes”:{
“name”:”Kerr Administration Building”,
“abbreviation”:”KAd”,
“latitude”:”44.5640654089″,
“longitude”:”-123.274740377″,
“summary”:”Kerr houses OSU’s top administrative offices and many services for students, including admissions, financial aid, registrar’s office and employment services. If you’d like a student-led campus tour, stop in 108 Kerr to make arrangements.”,
“description”:null,
“address”:”1500 SW Jefferson Avenue.”,
“city”:”Corvallis”,
“state”:”OR”,
“zip”:null,
“county”:null,
“telephone”:null,
“fax”:null,
“thumbnails”:[
“http://oregonstate.edu/campusmap/img/kad001.jpg”
],
“images”:[
null
],
“departments”:null,
“website”:”http://oregonstate.edu/campusmap/locations=766″,
“sqft”:null,
“calendar”:null,
“campus”:”corvallis”,
“type”:”building”,
“openHours”:{
}
},
“links”:{
“self”:”https://api.oregonstate.edu/v1/locations/2e9ee2d06066654f61a178560c2c137a”
}
}
]
}

I used the Microsoft ASP.NET Web API 2.2 Client Libraries NuGet package. This package has features to automagically deserialize JSON into plain ol’ class objects.

These are the class objects. .NET “generic” classes play an important role in the overall solution. Generic classes have a type parameter appended to their name, here <T>, where T is a naming convention used widely by .NET developers; wherever the type parameter (“T”) shows up in the class body is where the generic replacement is propagated when the type is constructed.

namespace JsonDataTransferObjects
{
  //first a few framework classes that can be reused later for other APIs...

  //root of all JSON returned by the OSU APIs.
  //note how the "links" and "data" fields 
  //  correspond with items of the same name in the JSON.
  public class RootObject<T>
  {
    public Links links { get; set; }
    public List<T> data { get; set; }
  }

  public class Links
  {
    public string self { get; set; }
    public string first { get; set; }
    public string last { get; set; }
    public string prev { get; set; }
    public string next { get; set; }
  }

  //Abstract (must inherit) class that corresponds to "id",
  // "type" and "attributes" of root object JSON
  public abstract class ObjectData<T>
  {
    public string id { get; set; }
    public string type { get; set; }
    public T attributes { get; set; }
  }

  //now classes for the solution at hand...

  //constructed type: class declared from a generic type 
  //  by supplying type arguments for its type parameters.
  //  now we will be able to work with RootObject<LocationData>,
  //  and the List in the "data" field will be of type LocationData
  public class LocationData : OregonState.Api.JsonDataTransferObjects.ObjectData<LocationAttributes>
  {
  }

  public class LocationAttributes
  {
    public string name { get; set; }
    public string abbreviation { get; set; }
    public string latitude { get; set; }
    public string longitude { get; set; }
    public string summary { get; set; }
    public string description { get; set; }
    public string address { get; set; }
    public string city { get; set; }
    public string state { get; set; }
    public string zip { get; set; }
    public string county { get; set; }
    public string telephone { get; set; }
    public string fax { get; set; }
    public List<string> thumbnails { get; set; }
    public List<string> images { get; set; }
    public object departments { get; set; }
    public string website { get; set; }
    public string sqft { get; set; }
    public string calendar { get; set; }
    public string campus { get; set; }
    public string type { get; set; }
    public LocationOpenHours openHours { get; set; }
  }

  public class LocationOpenHours
  {
    //todo: not sure what attribute name is
  }
}

Now, just enough code to get this test to pass (which it does!). Note the async and await keywords used for asynchronous programming in the .NET framework.

  [TestClass()]
  public class LocationServiceIntegrationTests {
    
      //initialize API service client, here constructed to handle the type LocationData
      private static readonly ApiServiceClient<LocationData> myServiceClient = MerthjTestApp1ApiServiceClientFactory.CreateLocationDataApiServiceClient();
  
      //gotcha: even unit tests, which normally do not return anything,
      // must now be "async" and return a "Task"
      // because of "await" keyword
      [TestMethod()]  
      async Task LocationServiceClient_Should_ReturnCorrectResultForQueryOnKerr() {
          RootObject<LocationData> result = await myServiceClient.Request("?q=kerr");
          Assert.AreEqual("Kerr Administration Building", result.data.Item[0].attributes.name);
      }
  }

Use factory pattern to construct the API client, because this is a complex process, and one that would lead to code duplication if simply NEW-ing the client in code.

public sealed class MerthjTestApp1ApiServiceClientFactory
{
	//todo: move to configuration
	// (here only because I liked to see the actual address)
	const string ApiOregonstateBaseAddressUriText = "https://api.oregonstate.edu";

	public static ApiServiceClient<LocationData> CreateLocationDataApiServiceClient()
	{
		//pass in a new LocationService, a service which makes actual calls
		// to the API (but we could also use "mock" service here...)
		//note use of Visual Studio's "My.Resources" to store Consumer Key and Consumer Secret
		//  in a resource file; resource file SHOULD NOT EVER be checked in
		//  to revision control, or your secrets are out there for all to see.
		return new ApiServiceClient<LocationData>(new LocationService(), ApiOregonstateBaseAddressUriText, "v1/locations", My.Resources.OSU_Developer_Portal_Secrets_Resource.ConsumerKey, My.Resources.OSU_Developer_Portal_Secrets_Resource.ConsumerSecret);
	}
}

An API service client is responsible for managing the access token required before each API call.

public class ApiServiceClient<T> {
    
    private readonly IApiService<T> myService;
    private readonly string myResourceRelativeUriText;
    private readonly string myBaseUriText;
    private readonly string myConsumerKey;
    private readonly string myConsumerSecret;
    
    //Lazy object is not constructed until its ".Value" method 
    // is called (a singleton) (see Me.CreateRequestAsync).
    // Not thread safe!
    private Lazy<Task<string>> myAccessToken = new Lazy<Task<string>>(new System.EventHandler(this.GetAccessTokenAsync));
    
    //no-arg constructor is private so clients may not use it
    private ApiServiceClient() {
    }
    
    //constructor required for use by clients
    public ApiServiceClient(IApiService<T> service, string baseAddressUriText, string resourceRelativeUriText, string consumerKey, string consumerSecret) {
        // todo: validate parameters
        this.myService = service;
        this.myResourceRelativeUriText = resourceRelativeUriText;
        this.myBaseUriText = baseAddressUriText;
        this.myConsumerKey = consumerKey;
        this.myConsumerSecret = consumerSecret;
    }
    
    //use the service to get the access token
    async Task<string> GetAccessTokenAsync() {
        Debug.WriteLine("Entering GetAccessTokenAsync");
        return await this.myService.GetAccessTokenAsync(this.myBaseUriText, this.myResourceRelativeUriText, this.myConsumerKey, this.myConsumerSecret);
    }
    
    async Task<ApiRequest> CreateRequestAsync(string query) {
        return new ApiRequest
        {
          //actually fetch the access token here!
          AccessToken = await this.myAccessToken.Value;
          BaseAddressUriText = this.myBaseUriText;
          ResourceRelativeUriText = this.myResourceRelativeUriText;
          Query = query;
        }
    }
    
    //clients can request API result as raw JSON string for troubleshooting...
    async Task<string> RequestAsString(string query) {
        return await this.myService.GetContentAndReadAsStringAsync(await this.CreateRequestAsync(query));
    }
    
    //most clients will use this method
    async Task<RootObject<T>> Request(string query) {
        return await this.myService.GetContentAndReadAsTypeAsync(await this.CreateRequestAsync(query));
    }
}

The API Service class is a messaging gateway, which encapsulates the API messaging code, and has strongly-typed methods. (See especially “public Task<RootObject> GetContentAndReadAsType(ApiRequest request)”.)

public abstract class ApiService<T> : IApiService<T>
{
	private static FormUrlEncodedContent CreateFormUrlEncodedContentForGetAccessToken(string consumerKey, string consumerSecret)
	{
		//Data required by OSU Get Access Token API
		var keys = {
			new KeyValuePair<string, string>("grant_type", "client_credentials"),
			new KeyValuePair<string, string>("client_id", consumerKey),
			new KeyValuePair<string, string>("client_secret", consumerSecret)
		};

		//Also sets content headers content type to "application/x-www-form-urlencoded".
		return new FormUrlEncodedContent(keys);
	}

	//"Async" declaration because we are calling "GetAsync" asynchronous method.
	//.NET compiler builds an absolutely CRAZY state machine in code behind the scenes.
	private async static Task<HttpResponseMessage> GetResponseAsync(HttpClient client, ApiRequest request)
	{
		client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", request.AccessToken);

		//Await-ing a result suspends its progress and yields control to the method that called it.
		//Could actually do other things in parallel here before we Await:
		// Dim responseTask = client.Get(request.ResourceRelativeUriText & request.Query)
		// DoIndependentWork()
		// Dim response =  await responseTask

		var response = await client.Get(request.ResourceRelativeUriText + request.Query);

		//ApiService doesn't know how to handle failed responses yet, so throw exception.
		if (!response.IsSuccessStatusCode) {
			throw new InvalidOperationException(response.ReasonPhrase);
		}

		return response;
	}

	private static HttpClient CreateHttpClient(string baseAddressUriText)
	{
		return new HttpClient { BaseAddress = new Uri(baseAddressUriText) };
	}

	public Task<string> GetAccessToken(string baseAddressUriText, string resourceRelativeUriText, string consumerKey, string consumerSecret)
	{
		//for a given resource Uri, like "v1/locations" or "v1/locations/", append segment for the access token to get "v1/locations/token"
		//todo: improve with something like http://stackoverflow.com/questions/372865/path-combine-for-urls
		var requestUri = new Uri(resourceRelativeUriText.TrimEnd('/') + "/token", UriKind.Relative);
		var content = CreateFormUrlEncodedContentForGetAccessToken(consumerKey, consumerSecret);

		//"Using" automatically and absolutely calls "Dispose" method on object at the code block.
		//Disposes any expensive and/or unmanaged resources, like an open connection stream.
		using (client = CreateHttpClient(baseAddressUriText)) {
			using (response = client.Post(requestUri, content)) {
				if (!response.IsSuccessStatusCode) {
					throw new InvalidOperationException(response.ReasonPhrase);
				}

				//Shorthand for:
				// var response = await response.Content.ReadAs(Of GetAccessTokenResponse)()
				// Return response.access_token
				return (response.Content.ReadAs<GetAccessTokenResponse>()).access_token;
			}
		}
	}

	//Read as string to support troubleshooting and curiosity.
	//Most clients should use the other method to "read as type," which reads data into strongly-typed classes
	public Task<string> GetContentAndReadAsString(ApiRequest request)
	{
		using (client = CreateHttpClient(request.BaseAddressUriText)) {
			using (response = GetResponseAsync(client, request)) {
				return response.Content.ReadAsString();
			}
		}
	}

	public Task<RootObject<T>> GetContentAndReadAsType(ApiRequest request)
	{
		using (client = CreateHttpClient(request.BaseAddressUriText)) {
			using (response = GetResponseAsync(client, request)) {
				//The magic deserialization of JSON
				// into .NET classes happens in this one line...
				//Declaration of ReadAs is:
				//  Public Shared Function ReadAs(Of T)(content As System.Net.Http.HttpContent) As System.Threading.Tasks.Task(Of T)
				//This class (ApiService) is generic so we can take advantage of ReadAs being generic.
				return response.Content.ReadAs<RootObject<T>>();
			}
		}
	}
}

And finally, the Location Service class inherits from API Service with the type parameter LocationData.

//Inherits ApiService, so we get its interface and functionality for free.
public class LocationService : ApiService<LocationData>
{
}

(This WordPress blog did not seem to have syntax highlighting for Visual Basic. So, I translated my existing code from VB.NET to C# using several online translators. There are bound to be errors introduced in the translation process. I know, I know. It’s not “cool” to write in VB… the poor under-appreciated language that can do everything–and more!–its currently-hip sibling C# can do. But I have more than 17 years of VB development under my belt, so not switching now just to be cool. I prefer to deliver business value rather than struggle with silly braces and semicolons. 🙂

Posted in API.