Hacking the government's kebabs
It’s a truth universally acknowledged that a man or women in possession of a skinful of beer must be in search of a kebab.
But the path to kebab nirvana is often paved with the slings and arrows of outrageous fortune.
Not any more - there’s an app for that.
Kebabbage is an app that I slung together at this weekend’s National Hack The Government Day with the help of Shaun McDonald. There were about 9,000 separate datasets on offer of varying degrees of interest and complexity, but one that caught my eye was the API offered by the Food Standards Agency. This aggregates the results of local authority Trading Standards inspections of food retailers, and allows searching by a variety of parameters such as location and authority.
There’s also data on hygiene scores, which suggested an approach - having donned beer googles it seems the dodgier the establishment, the better the kebab. So rather than go for the obvious “where’s the cleanest and nicest” approach, I decided to turn it on its head, and sort and highlight the lowest scores.
Overall, it’s a bit silly, and not especially useful. But then not every hackday creation can be about saving the world.
The how
The app relies on the core iOS MapKit
library, and two external APIs. The uk-postcodes.com API converts the geolocated latitude and longitude values to UK postcodes; and the Food Standards Agency api provides a JSON feed of rated premises based on the postcode.
Functionally, the app has a single view controller that manages the main interface, and acts as the delegate for two network client classes. These are subclasses of AFNetworking’s AFHTTPClient
- each one spins up with a custom init
method and then uses an AFJSONRequestOperation
to retrieve the relevant data.
Getting the data and plotting it onto the map has four stages:
- converting the lat/long position of the device to a UK postcode
- using the postcode to get a list of premises from the FSA API
- for each premises, converting the postcode to a lat/long pair
- plotting each premises on the map
Getting the initial lat/long-to-postcode isn’t any big issue, because it’s a single asynchronous call-and-response to the uk-postcodes.com API. Neither is getting the list of premises - again, that’s a single call-and-response which results in a blob of JSON.
Converting the postcode for each premises is a bit more involved, though. There can be over 100 premises returned in a single query, and converting each postcode takes time. Firing these off as a long series of individual requests would mean reliniquishing the chance of knowing when all had been processed.
The approach I used instead was to create a series of individual AFJSONRequestOperation
objects, and then batching these up with AFHTTPClient
’s enqueueBatchOfHTTPRequestOperations:progressBlock:completionBlock:
method. As the signature suggests, this takes an array of multiple AFJSONRequestOperation
operations, and a completion block which is fired after all the individual requests have been successfully processed (or have failed, whichever is the case). That allows code to be scheduled to run once everything has completed - which in this case was the placement of the MKAnnotation
objects onto the map.
-(void)getLatLongForArrayOfObjects:(NSArray *)outletsArray {
NSMutableArray *operationsArray = [[NSMutableArray alloc] init];
for (KBBOutlet *outlet in outletsArray) {
// GET http://uk-postcodes.com/postcode/<postcode>.json
NSString *postcode = [outlet postCode];
NSString *urlString = [NSString stringWithFormat:@"%@postcode/%@.json", kPostcodeApiUrl, postcode];
NSString *encodedURLString = [urlString stringByAddingPercentEscapesUsingEncoding:NSStringEncodingConversionAllowLossy];
NSURL *url = [NSURL URLWithString:encodedURLString];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
// SUCCESS
NSDictionary *geoDictionary = [JSON objectForKey:@"geo"];
NSString *latString = [geoDictionary objectForKey:@"lat"];
NSString *lngString = [geoDictionary objectForKey:@"lng"];
[outlet setLatitude:[latString floatValue]];
[outlet setLongitude:[lngString floatValue]];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
// FAILURE
NSLog(@"Error in PostCode: %@", error);
}];
[operation setShouldExecuteAsBackgroundTaskWithExpirationHandler:nil];
[operationsArray addObject:operation];
}
AFHTTPClient *client = [AFHTTPClient clientWithBaseURL:[NSURL URLWithString:kPostcodeApiUrl]];
[client enqueueBatchOfHTTPRequestOperations:operationsArray progressBlock:nil completionBlock:^(NSArray *operations) {
[self.delegate plotOutlets:outletsArray];
}];
}
The code is sitting up on GitHub at https://github.com/timd/Kebbabage
Some other post-hackday thoughts
I was somewhat suprised prior to the Hackday when I found out that it was partly sponsored by the Taxpayers Alliance. I’ve got a major problem with them as an opaquely-funded, right-wing blowhard pressure group that have an simplistic “everything private sector good, anything public sector bad” philosophy. Hackdays like this attract a large number of participants from all areas of the public sector, people who the TPA clearly look down their noses at - so at first glance there didn’t seem to be a natural fit.
I’m a tax-payer - in fact I’m pretty sure that I pay more UK tax than most of their funders - and they don’t speak for me. Tax is the price I pay for living in a civilised society, and the TPA espouse a set of small-minded, selfish, begger-thy-neighbour attitudes that grate on me badly. They know the price of everything, and the value of nothing.
Paul Clark puts it far more eloquently than I can.
The data they supplied was largely culled from Freedom of Information requests to local authorities - and the effort that has gone into compiling and consolidating this is worthy enough in and of itself. But there were some less-than-subtle hints that we might make want to spend the day digging through it in search of numbers that could later be turned into lazy Daily Mail-friendly “OMG councils spends bazillions on flowers for lesbian single parent playgroups” headlines.
That kind of political point scoring is not what I do hackdays for. I loathe and detest pretty much everything that our current government stands for; I’m not much more enamoured of the opposition alternatives. But there are better things that I can do with the skills that I’ve got available than digging up more mud for politicians to sling at each other. Doing that for unaccountable pressure groups is definitely off my agenda.
Having said all that, I don’t have a problem with involving the TPA in these kind of events. Who knows, perhaps some exposure to people who will willingly give up a day of their weekend to hack with data for no immediate reward than the inherent satisfaction might go some way to expose the shallowness of the TPA’s profit-centric philosophy. And looking at it from the point of view of Rewired State, they’re a) a source of data and b) are a fixture in the political playground, so they have a part to play.
But I found it quietly satisfying that if the TPA planned to buy the evening’s beer in the hope of someone finding them some dirt to sling, they probably left disappointed.