summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJochen Topf <jochen@topf.org>2011-03-07 18:33:34 +0100
committerJochen Topf <jochen@topf.org>2011-03-07 18:33:34 +0100
commitf3c295352f3ec814e80e204b5e785fc2505e05cd (patch)
tree73bae8cba775a70c9da5380990e19302f9a95856
parentc7bad4071f93e6f922c97e0d5d3c3797e3ca00ee (diff)
downloadtaginfo-f3c295352f3ec814e80e204b5e785fc2505e05cd.tar
taginfo-f3c295352f3ec814e80e204b5e785fc2505e05cd.tar.gz
add API documentation functions and start documenting the API
-rw-r--r--web/lib/api/db.rb136
-rw-r--r--web/lib/apidoc.rb68
-rw-r--r--web/lib/utils.rb6
-rw-r--r--web/public/css/taginfo.css24
-rwxr-xr-xweb/taginfo.rb9
-rw-r--r--web/views/about.erb6
-rw-r--r--web/views/apidoc.erb64
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 %>