Creating an api as a publicly accessible interface to your system can actually make your system better than it currently is!
A bold claim I know, but bear with me and I will try to justify this claim. Lets begin by imagining a large system which has evolved over time into something your customers like. It fits the purpose, it earns you money, it continues to grow and evolve. All sounds well. Now look behind the curtain, in the box, under the surface. Those little duck legs are paddling like mad just to keep the serene appearance on the surface. Your system has evolved into something if a mess beneath the surface. You're not at fault, its a fact of any software systems that over time commercial pressures mean that technical debt accrues and the system architecture is corrupted into a mess. Often UI and business logic boundaries are blurred, code duplication becomes rife, maintainability is generally reduced.
A nice clean architecture would have clear separation between the layers of the system in terms of the responsibilities, but more importantly in terms of the code base. In reality many systems blur these boundaries over time and code that should be in a business layer may be forced into the UI layer by time and commercial pressures. For a system with one UI this does not surface as a problem, but consider adding a second UI, quickly the business rules that you think are robust and well tested are being violated. How come? Well they were implemented in the previously sole UI, but are now being bypassed by the new UI. This highlights the build up of technical debt that putting the code in the wrong place causes. But as I say, you could live with this happily for years unless you introduce a new UI.
In a clean system the abstraction between layers should be such that any layer could be replaced an the system still function. If there is an overlap in responsibilities between layers this is not so straightforward.
Given the evolution of the technological landscape to a much more mobile, flexible one, with the desire to access everything from everywhere, there is an obvious drive towards supporting multiple interfaces to a system to accommodate this. Take a system that was written for a standard office of the past. It may have a big thick client with maybe just a shared database behind, or a thickish client with a server side engine that does the grunt work and a central database. To evolve either of these systems a web front end may be produced utilizing the same data. Where a server side engine existed this may be reused for consistency of functionality and minimal effort to create the new UI. If however any of the business logic existed in the client this will need to be replicated in the new web service. If we extend further and add mobile applications the logic will need to be placed in these too. And what about integrations with third party systems? Where does the logic sit there? We need to contain all the logic in a common business layer, just as our clean system architecture planned.
This is a problem I have seen many times over the years, and often when creating this one new UI the decision was taken to do the 'easy' thing at the time and duplicate the logic. Often this resulted in the logic being implemented inconsistently in the new UI. And worse, any bug found in either flavour of the system would only be fixed in that one flavour.
Recently I have been working on the addition of a rich RESTful API for a mature system, and where we find a hole in the business logic due to the API bypassing all UI layers the decision has been taken to do the right thing. Move the business logic into the business logic layer so all UIs have the same logic implemented by the common layer below.
All this sounds like a lot of bad coding has happened in the past, and that bad decisions have been made as to where to put code logic. But this is not the case in reality. Image a form in a system that allows you to enter data. A numeric field is entered, and the form restricts the format of the data. E.g. non negative, with enforced bounds and precision. The business layer of the system may well be the place that all the data validation is being performed, but what if some of the boundary conditions that should be guarded against are missed when writing this validation code? No-one made the decision to miss this validation. The testers thought of the boundary cases and tested them. The system held up robustly as the UI did not allow the user to enter the invalid data. But if the UI had not enforced these restriction then the invalid data may have gotten through. There was no way to test this. We thought the system was robust, and it was, but only via the single UI that was available to the testers to explore/exploit the system.
If in the scenario of the ever evolving technological landscape above we add a second UI, for whatever reason these restrictions may not be possible and the system becomes just that bit more fragile.
With an API, we can decide to implement no restrictions (other than type) on the data input and thus force the (common) business layer to take the responsibility for all the data validation.
The decision made to do this on the system I am currently writing the API for means that the API will be a little slower to produce, but more importantly the overall system will end up in a much better state of technical health. And the biggest benefit from this is that if a new UI is needed in the future that maybe does not even use the API but communicates directly with the business layer, we can be confident that the logic will be intact and robust.
So the addition of an API will not directly save your system, but can give you confidence that the system is fit and healthy enough to evolve further into a rapidly changing world that may put ever more challenging requirements on the core of the system.
A blog exploring topics of software development with specific focus on effective communication between the disciplines involved in the software lifecycle; and ways to solve some select mathematical problems using the .NET framework as a base, specifically coding in C#. This will document a learning journey shared by the author (me) and the readers (you and all your lovely friends) alike
Monday, 15 June 2015
Tuesday, 2 June 2015
OAuth in Winforms
The junior dev I am mentoring at my job was recently given the task of extending his knowledge of APIs and asked to demonstrate his newly gained knowledge by producing an application that consumes a third party API. More specifically a RESTful API.
In itself this does not seem the most taxing of tasks, but bear in mind that the junior dev has no web development experience, his only dev exposure in his current role has been on a winforms application. So to make this a targeted task, aimed at learning about RESTful APIs, it was decided a simple winforms application using the 4 main verbs would demonstrate sufficient understanding.
This however did raise a question, how to interact with an OAuth provider from a winforms application. This should be a simple matter, but it is something that is not well documented, especially in the documentation of most of the more famous APIs. There are plenty of tutorials for how to authenticate with an OAuth provider from a web site, and most of the APIs the junior dev looked at provided their own OAuth.
The final choice of the API to consume was Instagram, which provides great documentation for its OAuth when being consumed in a web site, but nothing for Winforms. This is not surprising, Winforms is an old technology, not something that you would expect to be used with a service like Intstagram, but why not? It should be possible (and is). But it is understandable that Instagram have not invested time in providing detailed documentation on how to do this. So here we go on how it was accomplished:
Firstly, the method of validating the user's claim of access to Instagram is via a web page hosted by Instagram. The documentation states
In itself this does not seem the most taxing of tasks, but bear in mind that the junior dev has no web development experience, his only dev exposure in his current role has been on a winforms application. So to make this a targeted task, aimed at learning about RESTful APIs, it was decided a simple winforms application using the 4 main verbs would demonstrate sufficient understanding.
This however did raise a question, how to interact with an OAuth provider from a winforms application. This should be a simple matter, but it is something that is not well documented, especially in the documentation of most of the more famous APIs. There are plenty of tutorials for how to authenticate with an OAuth provider from a web site, and most of the APIs the junior dev looked at provided their own OAuth.
The final choice of the API to consume was Instagram, which provides great documentation for its OAuth when being consumed in a web site, but nothing for Winforms. This is not surprising, Winforms is an old technology, not something that you would expect to be used with a service like Intstagram, but why not? It should be possible (and is). But it is understandable that Instagram have not invested time in providing detailed documentation on how to do this. So here we go on how it was accomplished:
Firstly, the method of validating the user's claim of access to Instagram is via a web page hosted by Instagram. The documentation states
which is fairly straightforward in a web app, but how do you do this in a winform application?
The answer is to host a web browser control within your application which will display the url above and be redirected upon completion of the authorization process. We found some code with a quick trawl of the search engines to perform this action in a pop up window:
string authorizationCode = StartTaskAsSTAThread(() => RunWebBrowserFormAndGetCode()).Result;
private static Task<T> StartTaskAsSTAThread<T>(Func<T> taskFunc)
{
TaskCompletionSource<T> tcs = new TaskCompletionSource<T>();
Thread thread = new Thread(() =>
{
try
{
tcs.SetResult(taskFunc());
}
catch (Exception e)
{
tcs.SetException(e);
}
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
return tcs.Task;
}
private static string RunWebBrowserFormAndGetCode()
{
Form webBrowserForm = new Form();
WebBrowser webBrowser = new WebBrowser();
webBrowser.Dock = DockStyle.Fill;
var uri = new Uri(@"https://api.instagram.com/oauth/authorize/?client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&response_type=code");
webBrowser.Url = uri;
webBrowserForm.Controls.Add(webBrowser);
string code = null;
WebBrowserDocumentCompletedEventHandler documentCompletedHandler = (s, e1) =>
{
string[] parts = webBrowser.Url.Query.Split(new char[] { '?', '&' });
foreach (string part in parts)
{
if (part.StartsWith("code="))
{
code = part.Split('=')[1];
webBrowserForm.Close();
}
else if (part.StartsWith("error="))
{
Debug.WriteLine("error");
}
}
};
webBrowser.DocumentCompleted += documentCompletedHandler;
Application.Run(webBrowserForm);
webBrowser.DocumentCompleted -= documentCompletedHandler;
return code;
}
which gets you the code included in the redirect URL. The CLIENT_ID you need to get from Instagram, register an application with them and it will be provided, and the REDIRECT_URL must match, but the location is unimportant, as the web browser will close on completion it will not be seen.
There is still one problem, when using Fiddler to inspect the successful API calls from the test bed of Apigee the access token has three parts period delimited, the user_id, an unknown part, and the code returned from the OAuth authentication stage. This is not well documented, and at this stage we are unable to generate the full access token.
All this highlights that the documentation of even well established APIs can at times be lacking for non-standard development paths.
Subscribe to:
Posts (Atom)