diff options
author | Jochen Topf <jochen@topf.org> | 2011-03-07 18:33:34 +0100 |
---|---|---|
committer | Jochen Topf <jochen@topf.org> | 2011-03-07 18:33:34 +0100 |
commit | f3c295352f3ec814e80e204b5e785fc2505e05cd (patch) | |
tree | 73bae8cba775a70c9da5380990e19302f9a95856 | |
parent | c7bad4071f93e6f922c97e0d5d3c3797e3ca00ee (diff) | |
download | taginfo-f3c295352f3ec814e80e204b5e785fc2505e05cd.tar taginfo-f3c295352f3ec814e80e204b5e785fc2505e05cd.tar.gz |
add API documentation functions and start documenting the API
-rw-r--r-- | web/lib/api/db.rb | 136 | ||||
-rw-r--r-- | web/lib/apidoc.rb | 68 | ||||
-rw-r--r-- | web/lib/utils.rb | 6 | ||||
-rw-r--r-- | web/public/css/taginfo.css | 24 | ||||
-rwxr-xr-x | web/taginfo.rb | 9 | ||||
-rw-r--r-- | web/views/about.erb | 6 | ||||
-rw-r--r-- | web/views/apidoc.erb | 64 |
7 files changed, 298 insertions, 15 deletions
diff --git a/web/lib/api/db.rb b/web/lib/api/db.rb index 4999466..d846a54 100644 --- a/web/lib/api/db.rb +++ b/web/lib/api/db.rb @@ -2,16 +2,40 @@ class Taginfo < Sinatra::Base @@filters = { - :characters_space => "characters='space'", - :characters_problematic => "characters='problem'", - :in_wiki => "in_wiki=1", - :not_in_db => "count_all=0" + :characters_space => { :expr => "characters='space'", :doc => 'only show keys with spaces' }, + :characters_problematic => { :expr => "characters='problem'", :doc => 'only show keys with problematic characters' }, + :in_wiki => { :expr => "in_wiki=1", :doc => 'only show keys that appear in the wiki' }, + :not_in_db => { :expr => "count_all=0", :doc => 'only show keys that do not appear in the database' } } - get '/api/2/db/keys' do + api(2, 'db/keys', { + :description => 'Get list of keys that are in the database or mentioned in any other source.', + :parameters => nil, + :paging => :optional, + :filter => @@filters, + :query => 'substring on key', + :sort => %w( key count_all count_nodes count_ways count_relations values_all users_all in_wiki in_josm in_potlatch length ), + :result => { + :key => :STRING, + :count_all => :INT, + :count_all_fraction => :FLOAT, + :count_nodes => :INT, + :count_nodes_fraction => :FLOAT, + :count_ways => :INT, + :count_ways_fraction => :FLOAT, + :count_relations => :INT, + :count_relations_fraction => :FLOAT, + :values_all => :INT, + :users_all => :INT, + :in_wiki => :BOOL, + :in_josm => :BOOL, + :in_potlatch => :BOOL + }, + :example => { :page => 1, :rp => 10, :filter => 'in_wiki', :sortname => 'key', :sortorder => 'asc' } + }) do if params[:filters] - filters = params[:filters].split(',').map{ |f| @@filters[f.to_sym] }.compact + filters = params[:filters].split(',').map{ |f| @@filters[f.to_sym][:expr] }.compact else filters = [] end @@ -113,7 +137,35 @@ class Taginfo < Sinatra::Base }.to_json end - get '/api/2/db/keys/overview' do + api(2, 'db/keys/overview', { + :description => 'Show statistics for nodes, ways, relations and total for this key.', + :parameters => :key, + :paging => :no, + :result => { + :nodes => { + :count => :INT, + :count_fraction => :FLOAT, + :values => :INT + }, + :ways => { + :count => :INT, + :count_fraction => :FLOAT, + :values => :INT + }, + :relations => { + :count => :INT, + :count_fraction => :FLOAT, + :values => :INT + }, + :all => { + :count => :INT, + :count_fraction => :FLOAT, + :values => :INT + }, + :users => :INT + }, + :example => { :key => 'highway' } + }) do key = params[:key] out = Hash.new @@ -139,7 +191,12 @@ class Taginfo < Sinatra::Base out.to_json end - get '/api/2/db/keys/distribution' do + api(2, 'db/keys/distribution', { + :description => 'Get map with distribution of this key in the database.', + :parameters => [:key], + :result => 'PNG image.', + :example => { :key => 'amenity' } + }) do key = params[:key] content_type :png @db.select('SELECT png FROM db.key_distributions'). @@ -147,7 +204,21 @@ class Taginfo < Sinatra::Base get_first_value() end - get '/api/2/db/keys/values' do + api(2, 'db/keys/values', { + :description => 'Get values used with a given key', + :parameters => [:key], + :paging => :optional, + :filter => { + :all => { :doc => 'no filter' }, + :nodes => { :doc => 'only values on tags used on nodes' }, + :ways => { :doc => 'only values on tags used on ways' }, + :relations => { :doc => 'only values on tags used on relations' } + }, + :sort => %w( value count_all count_nodes count_ways count_relations ), + :query => 'substring on value', + :result => { :value => :STRING, :count => :INT, :fraction => :FLOAT }, + :example => { :key => 'highway', :page => 1, :rp => 10, :sortname => 'count_ways', :sortorder => 'desc' } + }) do key = params[:key] filter_type = get_filter() @@ -193,7 +264,25 @@ class Taginfo < Sinatra::Base }.to_json end - get '/api/2/db/keys/keys' do + api(2, 'db/keys/keys', { + :description => 'Find keys that are used together with a given key.', + :parameters => [:key], + :paging => :optional, + :filter => { + :all => { :doc => 'no filter' }, + :nodes => { :doc => 'only values on tags used on nodes' }, + :ways => { :doc => 'only values on tags used on ways' }, + :relations => { :doc => 'only values on tags used on relations' } + }, + :sort => %w( together_count other_key from_fraction ), + :result => { + :other_key => :STRING, + :together_count => :INT, + :to_fraction => :FLOAT, + :from_fraction => :FLOAT + }, + :example => { :key => 'highway', :page => 1, :rp => 10, :sortname => 'together_count', :sortorder => 'desc' } + }) do key = params[:key] filter_type = get_filter() @@ -235,7 +324,7 @@ class Taginfo < Sinatra::Base }.to_json end - get '/api/2/db/popular_keys' do + api(2, 'db/popular_keys') do total = @db.count('popular_keys'). condition_if("key LIKE '%' || ? || '%'", params[:query]). get_first_value().to_i @@ -270,7 +359,30 @@ class Taginfo < Sinatra::Base }.to_json end - get '/api/2/db/tags/overview' do + api(2, 'db/tags/overview', { + :description => 'Show statistics for nodes, ways, relations and total for this tag.', + :parameters => [:key, :value], + :paging => :no, + :result => { + :nodes => { + :count => :INT, + :count_fraction => :FLOAT, + }, + :ways => { + :count => :INT, + :count_fraction => :FLOAT, + }, + :relations => { + :count => :INT, + :count_fraction => :FLOAT, + }, + :all => { + :count => :INT, + :count_fraction => :FLOAT, + } + }, + :example => { :key => 'highway', :value => 'residential' } + }) do key = params[:key] value = params[:value] diff --git a/web/lib/apidoc.rb b/web/lib/apidoc.rb new file mode 100644 index 0000000..26e4598 --- /dev/null +++ b/web/lib/apidoc.rb @@ -0,0 +1,68 @@ + +class APIDoc + + @@paths = {} + + attr_accessor :version, :path, :parameters, :paging, :filter, :sort, :query, :result, :description, :example + + def self.paths + @@paths + end + + def initialize(version, path, doc) + @version = version + @path = path + @doc = doc + + doc.each_pair do |k,v| + instance_variable_set("@#{k}".to_sym, v) + end + + @@paths[version] = {} unless @@paths[version] + @@paths[version][path] = self + end + + def complete_path + '/api/' + version.to_s + '/' + path + end + + def show_paging + paging || 'no' + end + + def show_filter + return '<i>none</i>' unless filter + list = [] + filter.keys.sort{ |a,b| a.to_s <=> b.to_s }.each do |f| + list << "<tt>#{f}</tt> (#{filter[f][:doc]})" + end + list.join('<br/>') + end + + def show_example + return '' if example.nil? + params = [] + example.each_pair do |k,v| + params << "#{k}=#{v}" + end + complete_path + '?' + params.join('&') + end + + def show_sort + return '<i>none</i>' unless sort + sort.map{ |s| "<tt>#{s}</tt>" }.join(', ') + end + + def show_query + return '<i>none</i>' unless query + query + end + + def show_result + return '<i>unknown</i>' if result.nil? + return result if result.is_a?(String) + '<pre>' + JSON.pretty_generate(result).gsub(/"(STRING|INT|FLOAT|BOOL)"/, '\1') + '</pre>' + end + +end + diff --git a/web/lib/utils.rb b/web/lib/utils.rb index 57fb46f..476d02b 100644 --- a/web/lib/utils.rb +++ b/web/lib/utils.rb @@ -175,6 +175,12 @@ def get!(path, &block) end end +# Like the 'get' method but specific for API calls, includes documentation for API calls +def api(version, path, doc=nil, &block) + APIDoc.new(version, path, doc) unless doc.nil? + get("/api/#{version}/#{path}", &block) +end + # return the base url for this site def base_url request.scheme + '://' + request.host + ':' + request.port.to_s diff --git a/web/public/css/taginfo.css b/web/public/css/taginfo.css index c914565..3764dee 100644 --- a/web/public/css/taginfo.css +++ b/web/public/css/taginfo.css @@ -311,11 +311,13 @@ table.list { table.list th { padding: 4px; font-weight: normal; + vertical-align: top; } table.list td { background-color: #ffffff; padding: 4px 10px; + vertical-align: top; } table.list td.border { @@ -410,6 +412,28 @@ table.drilldown td#feature { /* ========== */ +table.desc { + background-color: #f0f0f0; + padding: 6px; + width: 100%; +} + +table.desc th { + text-align: left; + vertical-align: top; + font-weight: normal; + width: 8em; + padding: 2px; +} + +table.desc td { + vertical-align: top; + background-color: #ffffff; + padding: 2px; +} + +/* ========== */ + div#instance_description a { text-decoration: underline; } diff --git a/web/taginfo.rb b/web/taginfo.rb index a1040ff..af9e4de 100755 --- a/web/taginfo.rb +++ b/web/taginfo.rb @@ -40,6 +40,7 @@ require 'lib/language.rb' require 'lib/sql.rb' require 'lib/sources.rb' require 'lib/reports.rb' +require 'lib/apidoc.rb' #------------------------------------------------------------------------------ @@ -279,6 +280,14 @@ class Taginfo < Sinatra::Base #-------------------------------------------------------------------------- + get '/apidoc' do + @title = 'API Documentation' + @breadcrumbs << @title + erb :apidoc + end + + #-------------------------------------------------------------------------- + load 'lib/instance.rb' load 'lib/api/db.rb' load 'lib/api/wiki.rb' diff --git a/web/views/about.erb b/web/views/about.erb index 78ce076..b7eb729 100644 --- a/web/views/about.erb +++ b/web/views/about.erb @@ -39,9 +39,9 @@ you. See the <a href="/download">download</a> section for more information.</p> <h2>API</h2> -<p>Taginfo data can be accessed through a REST API. The documentation should -appear here, but isn't done yet. Please look at the source code for Taginfo -or ask if you are interested.</p> +<p>Taginfo data can be accessed through a REST API. The documentation of the +API calls is <a href="/apidoc">here</a>, some general information +<a href="http://wiki.openstreetmap.org/wiki/Taginfo/API">on the wiki</a>.</p> <h3>Terms of Use</h3> diff --git a/web/views/apidoc.erb b/web/views/apidoc.erb new file mode 100644 index 0000000..07c2da7 --- /dev/null +++ b/web/views/apidoc.erb @@ -0,0 +1,64 @@ +<h1>API Documentation</h1> + +<p>See <a href="http://wiki.openstreetmap.org/wiki/Taginfo/API">the OSM wiki</a> for general information about the API.</p> + +<h2>Table of Contents</h2> + +<p style="color: red;">This list of API calls and their descriptions are not complete!</p> + +<ul> +<% APIDoc.paths.keys.sort.each do |version| + APIDoc.paths[version].keys.sort.each do |path| + doc = APIDoc.paths[version][path] %> + <li><a href="#<%= doc.complete_path.tr('/', '_')[1,1000] %>"><%= doc.complete_path %></li> +<% end + end %> +</ul> + +<% APIDoc.paths.keys.sort.each do |version| + APIDoc.paths[version].keys.sort.each do |path| + doc = APIDoc.paths[version][path] %> +<a name="<%= doc.complete_path.tr('/', '_')[1,1000] %>"></a> +<h2><%= doc.complete_path %></h2> +<table class="desc"> + </tr> + <tr> + <tr> + <th>Path:</th> + <td><tt><%= doc.complete_path %></tt></td> + </tr> + <tr> + <th>Description:</th> + <td><%= doc.description %></td> + </tr> + <tr> + <th>Parameters:</th> + <td><%= doc.parameters || '<i>none</i>' %></td> + </tr> + <tr> + <th>Paging:</th> + <td><%= doc.show_paging %></td> + </tr> + <tr> + <th>Filter:</th> + <td><%= doc.show_filter %></td> + </tr> + <tr> + <th>Sort:</th> + <td><%= doc.show_sort %></td> + </tr> + <tr> + <th>Query:</th> + <td><%= doc.show_query %></td> + </tr> + <tr> + <th>Result:</th> + <td><%= doc.show_result %></td> + </tr> + <tr> + <th>Example:</th> + <td><a href="<%= doc.show_example %>" target="_blank"><%= doc.show_example %></a></td> + </tr> +</table> +<% end + end %> |