# Best Practices

# Important

The Geodir Platform web services are a collection of HTTP interfaces to Geodir services providing geographic data for your maps applications. This guide discusses techniques for setting up web service requests and parsing the responses. For documentation specific to the Geocoding API, consult the developer’s guide.

# What is a web service?

Geodir Platform web services are an interface for requesting Maps API data from external services and using the data within your Maps applications. These services are designed to be used in conjunction with a map, as per the License Restrictions in the Geodir Terms of Service (opens new window).

The Maps APIs web services use HTTP requests to specific URLs, passing URL parameters as arguments to the services. Generally, these services return data in the HTTP request as either JSON or XML for parsing and/or processing by your application.

A typical Geocoding API web service request is generally of the following form:

[https://apis.geodir.co/geocoding/v1/responseFormat?parameteres](https://apis.geodir.co/geocoding/v1/responseFormat?parameteres)

where geocoding indicates the particular service requested and output indicates the response format (usually json or xml).

This guide describes some common practices useful for setting up your web service requests and processing your web service responses. Refer to the developer’s guide for full documentation of the Geocoding API.

Note: All Geocoding API applications require authentication. Get more information on authentication credentials.

# SSL Access

[https://apis.geodir.co/geocoding/v1/responseFormat?parameteres](https://apis.geodir.co/geocoding/v1/responseFormat?parameteres)

HTTPS is required for all Maps API web service requests containing user data, or developer identifiers. Requests made over HTTP that include sensitive data may be rejected.

# Valid URL

You may think that a "valid" URL is blank-evident, but that's not quite the case. A URL entered within an address bar in a browser, for example, may contain special characters (e.g. "上海+中國"); the browser needs to internally translate those characters into a different encoding before transmission. By the same token, any code that generates or accepts UTF-8 input might treat URLs with UTF-8 characters as "valid", but would also need to translate those characters before sending them out to a web server. This process is called URL-encoding (opens new window).

We need to translate special characters because all URLs need to conform to the syntax specified by the W3 Uniform Resource Identifier (opens new window) specification. In effect, this means that URLs must contain only a special subset of ASCII characters: the familiar alphanumeric symbols, and some reserved characters for use as control characters within URLs. The table below summarizes these characters:

Set characters URL usage
Alphanumeric a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 Text strings, scheme usage (http), port (8080), etc.
Unreserved - _ . ~ Text strings
Reserved ! * ' ( ) ; : @ & = + $ / ? % # [ ] Control characters and/or Text Strings

When building a valid URL, you must ensure that it contains only those characters shown above. Conforming a URL to use this set of characters generally leads to two issues, one of omission and one of substitution:

  • Characters that you wish to handle exist outside of the above set. For example, characters in foreign languages such as 上海+中國 need to be encoded using the above characters. By popular convention, spaces (which are not allowed within URLs) are often represented using the plus '+' character as well.
  • Characters exist within the above set as reserved characters, but need to be used literally. For example, ? is used within URLs to indicate the beginning of the query string; if you wish to use the string "? Macchupicchu," you'd need to encode the '?' character.

All characters to be URL-encoded are encoded using a '%' character and a two-character hex value corresponding to their UTF-8 character. For example, 上海+中國 in UTF-8 would be URL-encoded as %E4%B8%8A%E6%B5%B7%2B%E4%B8%AD%E5%9C%8B. The string ? Macchupicchu would be URL-encoded as %3F+Macchupicchu.

Some common characters that must be encoded are:

Unsafe Character Encoded Value
Space %20
" %22
+ %2B
, %2C
< %3C
> %3E
# %23
% %25
** **

Converting a URL that you receive from user input is sometimes tricky. For example, a user may enter an address as "Av Brasil&Bolivar" Generally, you should construct your URL from its parts, treating any user input as literal characters.

Additionally, URLs are limited to 8000 characters for all web services. For most services, this character limit will seldom be approached. However, note that certain services have several parameters that may result in long URLs.

# Polite Use of Geodir APIs

Poorly designed API clients can place more load than necessary on both the Internet and Geodir's servers. This section contains some best practices for clients of the APIs. Following these best practices can help you avoid your application being blocked for inadvertent abuse of the APIs.

# Exponential Backoff

In rare cases something may go wrong serving your request; you may receive a 4XX or 5XX HTTP response code, or the TCP connection may simply fail somewhere between your client and Geodir's server. Often it is worthwhile re-trying the request as the followup request may succeed when the original failed. However, it is important not to simply loop repeatedly making requests to Geodir's servers. This looping behavior can overload the network between your client and Geodir causing problems for many parties.

A better approach is to retry with increasing delays between attempts. Usually the delay is increased by a multiplicative factor with each attempt, an approach known as Exponential Backoff (opens new window).

También debe tener cuidado de que no haya un código de reintento más alto en la cadena de llamadas de la aplicación que conduzca a solicitudes repetidas en rápida sucesión.

# Synchronized Requests

Large numbers of synchronized requests to Geodir's APIs can look like a Distributed Denial of Service (DDoS) attack on Geodir's infrastructure, and be treated accordingly. To avoid this, you should make sure that API requests are not synchronized between clients.

For example, consider an application that displays the time in the current time zone. This application will probably set an alarm in the client operating system waking it up at the start of the minute so that the displayed time can be updated. The application should not make any API calls as part of the processing associated with that alarm.

Making API calls in response to a fixed alarm is bad as it results in the API calls being synchronized to the start of the minute, even between different devices, rather than being distributed evenly over time. A poorly designed application doing this will produce a spike of traffic at sixty times normal levels at the start of each minute.

Instead, one possible good design is to have a second alarm set to a randomly chosen time. When this second alarm fires the application calls any APIs it needs and stores the results. When the application wants to update its display at the start of the minute, it uses previously stored results rather than calling the API again. With this approach, API calls are spread evenly over time. Further, the API calls do not delay rendering when the display is being updated.

Aside from the start of the minute, other common synchronization times you should be careful not to target are at the start of an hour, and the start of each day at midnight.

# Processing Responses

The Geodir web services provide responses which are easy to understand, but not exactly user friendly. When performing a query, rather than display a set of data, you probably want to extract a few specific values. Generally, you will want to parse responses from the web service and extract only those values which interest you.

The parsing scheme you use depends on whether you are returning output in XML or JSON. JSON responses, being already in the form of Javascript objects, may be processed within Javascript itblank on the client; XML responses should be processed using an XML processor and an XML query language to address elements within the XML format. We use XPath in the following examples, as it is commonly supported in XML processing libraries.

# Processing XML with XPath

XML is a relatively mature structured information format used for data interchange. Although it is not as lightweight as JSON, XML does provide more language support and more robust tools. Code for processing XML in Java, for example, is built into the javax.xml packages.

When processing XML responses, you should use an appropriate query language for selecting nodes within the XML document, rather than assume the elements reside at absolute positions within the XML markup. XPath is a language syntax for uniquely describing nodes and elements within an XML document. XPath expressions allow you to identify specific content within the XML response document.

# XPath Expressions

Some familiarity with XPath goes a long way towards developing a robust parsing scheme. This section will focus on how elements within an XML document are addressed with XPath, allowing you to address multiple elements and construct complex queries.

XPath uses expressions to select elements within an XML document, using a syntax similar to that used for directory paths. These expressions identify elements within an XML document tree, which is a hierarchical tree similar to that of a DOM. Generally, XPath expressions are greedy, indicating that they will match all nodes which match the supplied criteria.

We'll use the following abstract XML to illustrate our examples:

<WebServiceResponse>
 <status>OK</status>
 <result>
  <type>sample</type>
  <name>Sample XML</name>
  <location>
   <lat>37.4217550</lat>
   <lng>-122.0846330</lng>
  </location>
 </result>
 <result>
  <message>The secret message</message>
 </result>
</WebServiceResponse>

# Node Selection in Expressions

XPath selections select nodes. The root node encompasses the entire document. You select this node using the special expression "/". Note that the root node is not the top-level node of your XML document; actually, it resides one level above this top-level element and includes it.

Element nodes represent the various elements within the XML document tree. A WebServiceResponse element, for example, represents the top-level element returned in our sample service above. You select individual nodes either via absolute or relative paths, indicated by the presence or absence of a leading "/" character.

  • Absolute path: the "/WebServiceResponse/result" expression selects all result nodes that are children of the WebServiceResponse node. (Note that both of these elements descend from the root node "/".)
  • Relative path from the current context: the expression "result" would match any result elements within the current context. Generally, you shouldn't have to worry about context, as you're usually processing web service results via a single expression.

Either of these expressions may be augmented through addition of a wildcard path, indicated with a double-slash ("//"). This wildcard indicates that zero or more elements may match in the intervening path. The XPath expression "//address_standard," for example, will match all nodes of that name in the current document.

By default, XPath expressions match all elements. You can restrict the expression to match a certain element by providing a predicate, which is enclosed in square brackets ([]). The XPath expression "/GeocodeResponse/result[2] always returns the second result, for example.

# Processing JSON with JavaScript

JSON (Javascript Object Notation) has an obvious advantage over XML in that the response is lightweight. Parsing such a result is trivial in JavaScript as the format is already a valid Javascript object. For example, to extract the value of the 'address_standard' keys within a JSON result object, simply access them using the following code:

for (i = 0; i < myJSONResult.results.length; i++) {
  myAddress[i] = myJSONResult.results[i].formatted_address;
}

Note that because JSON may contain multiple values, it's wisest to iterate over the length of the results array if you want to capture all possible values. In practice, you may wish to only return the first result (results[0]), however.

Parsing JSON in other languages is only moderately more difficult. The following Python example initiates a Geocoding Web Service request and displays all resulting address_standard values to the user within an array:

import json
import urllib.request

### The maps_key defined below isn't a valid Geodir API Key.
### You need to obtain your own API Key.
### See https://docs.geodir.co/geocoding/obtain-your-api-key
API_KEY = "YOUR_API_KEY"
GEOCODE_BASE_URL = "https://apis.geodir.co/geocoding/v1/json"

def geocode(address):
    # Join the parts of the URL together into one string.
    params = urllib.parse.urlencode({"address": address, "key": API_KEY,})
    url = f"{GEOCODE_BASE_URL}?{params}"

    result = json.load(urllib.request.urlopen(url))

    if result["status"] in ["OK", "ZERO_RESULTS"]:
        return result["results"]

    raise Exception(result["error_message"])

if __name__ == "__main__":
    results = geocode(address="Av+Arequipa")
    print(json.dumps([s["address_standard"] for s in results], indent=2))

Output:

[
  "Miraflores, Lima, PE"
]
Last updated: 09/18/2023, 10:30:49 PM