<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
</head>
<body bgcolor="#FFFFFF" text="#000000">
Hi,<br>
<br>
I would like to share with you the first artifacts of the effort to
build a sustainable API documentation (not only) for Katello. Last
year I've proposed a master thesis topic on the REST api
documentation tool for Rails framework at local university and after
a while a student Pavel Pokorny responded positively to this topic
and so the story began.<br>
<br>
The original idea came from my hobby experimental project active_doc
(<a class="moz-txt-link-freetext" href="https://github.com/iNecas/active_doc">https://github.com/iNecas/active_doc</a>) which aimed to provide DSL to
describe the code instead of just using plain comments. The
advantage of this approach is that you have the documentation
available on the run-time so that you can do additional things like
validating that the coming requests are consistent with the
documentation or serve the documentation to the client directly etc.<br>
<br>
The project coming from this cooperation is called rails-restapi
(<a class="moz-txt-link-freetext" href="https://github.com/Pajk/rails-restapi">https://github.com/Pajk/rails-restapi</a> - we haven't found better
name for that so far:). You can see a sample output at <br>
<br>
<a class="moz-txt-link-freetext" href="http://restapi-likes.rhcloud.com/">http://restapi-likes.rhcloud.com/</a><br>
<a class="moz-txt-link-freetext" href="http://restapi-likes.rhcloud.com/apidoc#twitter_example">http://restapi-likes.rhcloud.com/apidoc#twitter_example</a> (you can
get there from the bottom of previous page)<br>
<a class="moz-txt-link-freetext" href="http://restapi-likes.rhcloud.com/apidoc#twitter_example/lookup">http://restapi-likes.rhcloud.com/apidoc#twitter_example/lookup</a><br>
<br>
<br>
We can divide the whole project into 4 parts:<br>
<br>
<b>1. DSL for describing the requests</b>, e.g.:<br>
<br>
api :POST, "/organizations/:organization_id/environments", "Create
an environment in organization"<br>
param :organization_id, :identifier, :required => true<br>
param :environment, Hash do<br>
param :name, :identifier, :required => true, :desc =>
"Name of the new environment, it has to be unique in the
organization"<br>
param :prior, :number, :required => true, :desc => "Id of
the prior environment. it has to be either Library or an environment
at the end of a chain"<br>
param :description, String<br>
end<br>
error :code => 400, :desc => "In case the name is already
taken or the prior is neither Library nor environment at the end of
the chain"<br>
desc <<-DESC<br>
Long description for the action. You can use RDoc formatting for
this description.<br>
DESC<br>
def create<br>
# ...<br>
end<br>
<br>
We can describe what path and http method to use do to some action.<br>
With keyword param we specify the arguments we expect. We can also
specify what value we expect (e.g. with type like Fixnum, String;
with enumerating acceptable values (["redhat", "custom"]), regular
expression (/^\<a class="moz-txt-link-abbreviated" href="mailto:w+@\w+\.\w">w+@\w+\.\w</a>{2,3}$) or with custom validator
(:identifier, :number)).<br>
You can also specify what error codes might the action return. With
desc you can write longer documentation using RDoc formatting.<br>
<br>
This DSL can be used before each method of an action. You can
similarly give some basic documentation for the resource. (You can
take a look at fully described controller at
<a class="moz-txt-link-freetext" href="https://github.com/iNecas/katello/blob/restapi/src/app/controllers/api/environments_controller.rb">https://github.com/iNecas/katello/blob/restapi/src/app/controllers/api/environments_controller.rb</a>)<br>
<br>
<b>2. Validator for making sure the documentation is up-to date:</b><br>
<br>
When you say:<br>
<br>
param :provider_type, ["redhat", "custom"]<br>
<br>
it would be nice to make sure that these are the only values we
support. Therefore restapi provides a validation mode (configurable
in config/initializers/restapi.rb). When running in this mode, it
will fail when you try to call it with a value not valid with the
description. It's ideal combination with running API or CLI tests
with this mode so that you can make sure that the requests are
really consistent with the description.<br>
<br>
<b>3. Engine providing the documentation through API<br>
</b><br>
The plugin is using Rails Engine architecture to inject it's own
routes to the application where the documentation can be requested
for further processing (in JSON format).<br>
<br>
<b>4. HTML client to the documentation server</b><br>
<br>
There is a sample HTML client provided with the restapi gem, that is
based on backbone.js. It uses the DOC API described in point 3.<br>
<br>
If you run my branch of katello
(<a class="moz-txt-link-freetext" href="https://github.com/iNecas/katello/tree/restapi">https://github.com/iNecas/katello/tree/restapi</a> - remember to run
bundle install before and run the app itself in devel mode unless
you are willing to customize your apache configuration for static
assets)<br>
<br>
<b>Automatically generated doc based on CLI tests = API
documentation line</b><br>
<br>
I've put together a tool for kick-starting the first documentation
based on requests to the API. The idea is to run all cli tests,
watch the requests and generate the documentation based on the
requests, responses and config/routes.rb. You can see the results in
my branch restapi (<a class="moz-txt-link-freetext" href="https://github.com/iNecas/katello/tree/restapi">https://github.com/iNecas/katello/tree/restapi</a>).
It's not 100% exact but is very useful for starting.<br>
<br>
Before you start run bundle install (I've put a gem restapi.0.0.3.kt
with some tweaks not yet in the upstream version to a custom gem
repo <a class="moz-txt-link-freetext" href="http://inecas.fedorapeople.org/rubygems/">http://inecas.fedorapeople.org/rubygems/</a>, it's mentioned in the
Gemfile).<br>
<br>
You can run it in development environment and get the instant
feedback for you changes (in exchange for longer reload time), in
production it's much faster because the description not being
reloaded.<br>
<br>
When you go to:<br>
<br>
<a class="moz-txt-link-freetext" href="https://localhost/katello/apidoc">https://localhost/katello/apidoc</a><br>
<br>
you can see what all possible requests you can make to the API (some
paths might surprise you but that's what our routes.rb says = we
need to do some cleenup there).<br>
<br>
I've updated documentation for environments a bit so that you can
see what it might look like:<br>
<br>
<a class="moz-txt-link-freetext" href="https://localhost/katello/apidoc#environments">https://localhost/katello/apidoc#environments</a><br>
<br>
and what a action description might look like:<br>
<br>
<a class="moz-txt-link-freetext" href="https://localhost/katello/apidoc#environments/create">https://localhost/katello/apidoc#environments/create</a><br>
<br>
There is still some work to do but I would like to hear your
feedback, suggestions, options on this approach. I hope it's the
first step to get more consistent and usable API for our project.<br>
<br>
<pre class="moz-signature" cols="72">--
Ivan</pre>
</body>
</html>