1 # Changing the Appearance of Results in the Server API
 
   3 The Nominatim Server API offers a number of formatting options that
 
   4 present search results in [different output formats](../api/Output.md).
 
   5 These results only contain a subset of all the information that Nominatim
 
   6 has about the result. This page explains how to adapt the result output
 
   7 or add additional result formatting.
 
   9 ## Defining custom result formatting
 
  11 To change the result output, you need to place a file `api/v1/format.py`
 
  12 into your project directory. This file needs to define a single variable
 
  13 `dispatch` containing a [FormatDispatcher](#formatdispatcher). This class
 
  14 serves to collect the functions for formatting the different result types
 
  15 and offers helper functions to apply the formatters.
 
  17 There are two ways to define the `dispatch` variable. If you want to reuse
 
  18 the default output formatting and just make some changes or add an additional
 
  19 format type, then import the dispatch object from the default API:
 
  22 from nominatim_api.v1.format import dispatch as dispatch
 
  25 If you prefer to define a completely new result output, then you can
 
  26 create an empty dispatcher object:
 
  29 from nominatim_api import FormatDispatcher
 
  31 dispatch = FormatDispatcher()
 
  34 ## The formatting function
 
  36 The dispatcher organises the formatting functions by format and result type.
 
  37 The format corresponds to the `format` parameter of the API. It can contain
 
  38 one of the predefined format names or you can invent your own new format.
 
  40 API calls return data classes or an array of a data class which represent
 
  41 the result. You need to make sure there are formatters defined for the
 
  42 following result types:
 
  44 * StatusResult (single object, returned by `/status`)
 
  45 * DetailedResult (single object, returned by `/details`)
 
  46 * SearchResults (list of objects, returned by `/search`)
 
  47 * ReverseResults (list of objects, returned by `/reverse` and `/lookup`)
 
  48 * RawDataList (simple object, returned by `/deletable` and `/polygons`)
 
  50 A formatter function has the following signature:
 
  53 def format_func(result: ResultType, options: Mapping[str, Any]) -> str
 
  56 The options dictionary contains additional information about the original
 
  57 query. See the [reference below](#options-for-different-result-types)
 
  58 about the possible options.
 
  60 To set the result formatter for a certain result type and format, you need
 
  61 to write the format function and decorate it with the
 
  62 [`format_func`](#nominatim_api.FormatDispatcher.format_func)
 
  65 For example, let us extend the result for the status call in text format
 
  66 and add the server URL. Such a formatter would look like this:
 
  69 from nominatim_api import StatusResult
 
  71 @dispatch.format_func(StatusResult, 'text')
 
  72 def _format_status_text(result, _):
 
  73     header = 'Status for server nominatim.openstreetmap.org'
 
  75         return f"{header}\n\nERROR: {result.message}"
 
  77     return f"{header}\n\nOK"
 
  80 If your dispatcher is derived from the default one, then this definition
 
  81 will overwrite the original formatter function. This way it is possible
 
  82 to customize the output of selected results.
 
  86 You may also define a completely different output format. This is as simple
 
  87 as adding formatting functions for all result types using the custom
 
  91 from nominatim_api import StatusResult
 
  93 @dispatch.format_func(StatusResult, 'chatty')
 
  94 def _format_status_text(result, _):
 
  96         return f"The server is currently not running. {result.message}"
 
  98     return "Good news! The server is running just fine."
 
 101 That's all. Nominatim will automatically pick up the new format name and
 
 102 will allow the user to use it. There is no need to implement formatter
 
 103 functions for all the result types, when you invent a new one. The
 
 104 available formats will be determined for each API endpoint separately.
 
 105 To find out which formats are available, you can use the `--list-formats`
 
 106 option of the CLI tool:
 
 109 me@machine:planet-project$ nominatim status --list-formats
 
 110 2024-08-16 19:54:00: Using project directory: /home/nominatim/planet-project
 
 115 me@machine:planet-project$
 
 118 The `debug` format listed in the last line will always appear. It is a
 
 119 special format that enables debug output via the command line (the same
 
 120 as the `debug=1` parameter enables for the server API). To not clash
 
 121 with this built-in function, you shouldn't name your own format 'debug'.
 
 123 ### Content type of new formats
 
 125 All responses will be returned with the content type application/json by
 
 126 default. If your format produces a different content type, you need
 
 127 to configure the content type with the `set_content_type()` function.
 
 129 For example, the 'chatty' format above returns just simple text. So the
 
 130 content type should be set up as:
 
 133 from nominatim_api.server.content_types import CONTENT_TEXT
 
 135 dispatch.set_content_type('chatty', CONTENT_TEXT)
 
 138 The `content_types` module used above provides constants for the most
 
 139 frequent content types. You set the content type to an arbitrary string,
 
 140 if the content type you need is not available.
 
 142 ## Formatting error messages
 
 144 Any exception thrown during processing of a request is given to
 
 145 a special error formatting function. It takes the requested content type,
 
 146 the status code and the error message. It should return the error message
 
 147 in a form appropriate for the given content type.
 
 149 You can overwrite the default formatting function with the decorator
 
 153 import nominatim_api.server.content_types as ct
 
 155 @dispatch.error_format_func
 
 156 def _format_error(content_type: str, msg: str, status: int) -> str:
 
 157     if content_type == ct.CONTENT_XML:
 
 158         return f"""<?xml version="1.0" encoding="UTF-8" ?>
 
 159                      <message>{msg}</message>
 
 161     if content_type == ct.CONTENT_JSON:
 
 164     return f"ERROR: {msg}"
 
 168 ## Debugging custom formatters
 
 170 The easiest way to try out your custom formatter is by using the Nominatim
 
 171 CLI commands. Custom formats can be chosen with the `--format` parameter:
 
 174 me@machine:planet-project$ nominatim status --format chatty
 
 175 2024-08-16 19:54:00: Using project directory: /home/nominatim/planet-project
 
 176 Good news! The server is running just fine.
 
 177 me@machine:planet-project$
 
 180 They will also emit full error messages when there is a problem with the
 
 181 code you need to debug.
 
 184     In some cases, when you make an error with your import statement, the
 
 185     CLI will not give you an error but instead tell you, that the API
 
 186     commands are no longer available:
 
 188         me@machine: nominatim status
 
 189         usage: nominatim [-h] [--version] {import,freeze,replication,special-phrases,add-data,index,refresh,admin} ...
 
 190         nominatim: error: argument subcommand: invalid choice: 'status'
 
 192     This happens because the CLI tool is meant to still work when the
 
 193     nominatim-api package is not installed. Import errors involving
 
 194     `nominatim_api` are interpreted as "package not installed".
 
 196     Use the help command to find out which is the offending import that
 
 199         me@machine: nominatim -h
 
 200         ... [other help text] ...
 
 201         Nominatim API package not found (was looking for module: nominatim_api.xxx).
 
 207 ::: nominatim_api.FormatDispatcher
 
 210         group_by_category: False
 
 214 ::: nominatim_api.utils.json_writer.JsonWriter
 
 217         group_by_category: False
 
 219 ### Options for different result types
 
 221 This section lists the options that may be handed in with the different result
 
 222 types in the v1 version of the Nominatim API.
 
 230 | Option          | Description |
 
 231 |-----------------|-------------|
 
 232 | locales         | [Locale](../library/Result-Handling.md#locale) object for the requested language(s) |
 
 233 | group_hierarchy | Setting of [group_hierarchy](../api/Details.md#output-details) parameter |
 
 234 | icon_base_url   | (optional) URL pointing to icons as set in [NOMINATIM_MAPICON_URL](Settings.md#nominatim_mapicon_url) |
 
 238 | Option          | Description |
 
 239 |-----------------|-------------|
 
 240 | query           | Original query string |
 
 241 | more_url        | URL for requesting additional results for the same query |
 
 242 | exclude_place_ids | List of place IDs already returned |
 
 243 | viewbox         | Setting of [viewbox](../api/Search.md#result-restriction) parameter |
 
 244 | extratags       | Setting of [extratags](../api/Search.md#output-details) parameter |
 
 245 | namedetails     | Setting of [namedetails](../api/Search.md#output-details) parameter |
 
 246 | addressdetails  | Setting of [addressdetails](../api/Search.md#output-details) parameter |
 
 250 | Option          | Description |
 
 251 |-----------------|-------------|
 
 252 | query           | Original query string |
 
 253 | extratags       | Setting of [extratags](../api/Search.md#output-details) parameter |
 
 254 | namedetails     | Setting of [namedetails](../api/Search.md#output-details) parameter |
 
 255 | addressdetails  | Setting of [addressdetails](../api/Search.md#output-details) parameter |