OAF makes it easy and fast to get to the image you want.
Open Asset is a proprietary system that stores photos and other assets for AEC companies.
It has a REST API that allows developers to access and manipulate the database but that API is hard to use and slow.
The OA REST API (look at all those acronyms!) requires 4 round trips to the server to retrieve an image. This was unacceptably slow for our needs. It also needed code that was overly complex for a regular person* to write. (*i.e. a non-developer.)
The OA REST API has a very direct mapping to the guts of the database. OAF exists to abstract away the details of that database and phrase the requests in terms of what people want, not how to get it.
As well as abstracting the API provided by Open Asset to make it easier to call, it also has a caching layer. The caching reduces the time take to fetch an image from about 5 seconds to regular image GET timing. I.e. about 125ms to get an image that OAF has reached vs 5000ms to get an image that OAF hasn’t cached.
We think that a normalised API is a bad thing. Others agree -- tldr: making multiple requests for a single image sucks.
OAF is an acronym for Open Asset Fixer.
- As a marketing person I want to be able to put the best photo of a project onto a web page so that I can get a submission done quickly and not be exposed to risk.
- As a web developer I want to be able to write a page that has a grid of the best photos for all the projects.
- As a web developer I want to be able to show a project photo on a web page along with some of its meta data so that we can fulfil copyright obligations to the photographer.
- As an architect I want to be able to put several photos into a blog post so that I can illustrate a story about the project I worked on.
To get an image you can either use a 303 redirect or a JSON request.
To construct the request:
/:project_number/:tag/:index/:size
So in the real world that would be:
http://oaf.com/S0910004/main/0/web_view
That would get you the highest rated image from the S0910004 project, with the webview size.
The options for each part are:
Not much in the way of option here! You either have that project or you don’t!
This one is kind of secret sauce. We rolled our own tagging system to allow freeform tagging. You can use if if you like, it’s pretty cool, but it’s not documented here yet (soon). Just set this to main and you’ll be fine.
This tells OAF which photo to get. The photos need to be ranked using the OA system. The best image is at index 0, second best at 1 etc. If there is a clash (two photos ranked best) then it’s pot luck which one you’ll get.
Size must be one of: square, thumbnail, small, web_view or medium. The actual size that you’ll get back is defined in your OA settings somewhere.
One day my prince will come...
The central concept used in OAF is that of Data Access Objects (DAO).
In short, a DAO is an object that abstracts over the ‘accessing data’ part and presents a simple object oriented way to work with the objects. The objects in question are defined by the Open Asset API’s exposed resources listed here.
When accessing an image for a project we need to send a get request to:
/Projects
- to get the images associated with a project number (code in OA parlance)/Files
- to get the image sizes associated with an image/Files/:id/Sizes
- to get the url a particular size is located at
When encapsulated using DAO objects accessing a particular project’s image url looks like:
p = get_project()
p.images[0][‘web_view’].url
In order to make this happen the models need a way to access the data remotely. This is done with two entwined super classes, Model and DataSource, intended to be inherited from by implementations. Inside of the Project model, for example, the images method is implemented like so:
class Model
...
def get query
@data_source.get query => @oa_id
end
...
end
class Project < Model
...
def images
get :image
end
...
end
Note that the data source is passed in to the model’s constructor. Below is a list of the classes/files.
- core
- datasource
- model
- models
- Project
- Image
- Size
- data sources
- Open Asset - uses rest_client gem to fetch from OA’s API
- Redis - uses redis gem to cache results
- Double - combines two above data sources into one which will automatically fetch from redis if it exists, otherwise fetch from OA then cache the result in redis
- controller
The data source accepts a dictionary of symbol to id (e.g. { :project => ‘S0910004’ }
). The symbol is turned into a string, capitalized, then passed to Kernel.const_get to turn it into a reference to the class Project. If a model ever had a name that couldn’t be easily transformed in the above way to it’s constant representation then the data source would not work on it. It also requires that the models not be in a separate module namespace.
This is done to simplify things. However a more robust and less ‘clever’ way of doing things would be to have a dictionary somewhere of symbols to classes, e.g.:
class_map = {
project: Project,
image: Image,
other_class: Namespace::OtherClass
}
- make it less impotent (i.e. include images in the to_json). NB: Projects#to_json was neutered because to_json is used to store it in redis. Using the to_json options parameter to tell it whether or not to include images in it’s json representation would be a good way to go.
- add photographer, copyright holder, etc