This is a client library for the OpenCage Forward and Reverse geocoding APIs. You will need to have an API key to be able to issue requests. You can register for free here.
Before using this library please have a look at best practices for using the OpenCage API, particularly OpenCage's advice for how to format forward geocoding queries.
You'll need to install sbt first. Then you can just run:
sbt clean test package
To perform forward geocoding, all you need to do is call the forwardGeocode
method, as is shown before:
val client = new OpenCageClient(authKey)
try {
val responseFuture = client.forwardGeocode("address to forward geocode")
val response = Await.result(responseFuture, 5 seconds)
}
finally {
client.close()
}
Note that the client is non-blocking, so if you're handling responses in an async way, you won't need to await for the future.
To perform reverse geocoding, all you need to do is call the reverseGeocode
method with the latitude/longitude you want to reverse geocode, as is shown before:
val client = new OpenCageClient(authKey)
try {
val latitude = 52.51627f
val longitue = 3.37769f
val responseFuture = client.reverseGeocode(latitude, longitude)
val response = Await.result(responseFuture, 5 seconds)
}
finally {
client.close()
}
Sometimes you query the OpenCage API and it cannot geocode your query, it was a valid query, but no results were found. You can check if that's the case by checking status code of the response and emptiness of the results.
val response = Await.result(responseFuture, 5.seconds)
if (response.status.code == 200 & response.results.isEmpty) {
println("Ups, we can't geolocate your query")
}
Note that the client is non-blocking, so if you're handling responses in an async way, you won't need to await for the future.
To make sure you don't leave resources dangling around, make sure you call the close()
method on the client when you don't need it anymore, so any connections still open can be closed.
The parameters sent by the client to the OpenCage APIs can be overridden (see this), by using the params
parameter:
val bounds = Some((minimumLongitude, minimumLatitude, maximumLongitude, maximumLatitude))
val params = OpenCageClientParams(abbreviate = true,
bounds = bounds,
countryCodes = List("fr,bl,gf,gp,mf,mq,nc,pf,pm,re,tf,wf,yt"),
language = "fr",
limit = 10,
minConfidence = 5,
withoutAnnotations = false,
withoutDeduplication = true,
withoutRecord = true)
client.reverseGeocode(latitude, longitude, params)
This is particularly useful for forward geocoding to help improve your results.
Below you have a code snippet of a minimal application using OpenCage client. First create a minimal project scaffolding
by issuing sbt new scala/scala-seed.g8
. Then place in src/main/scala/example/
this file
package com.github.nmdguerreiro.opencage.geocoder
import scala.concurrent.Await
import scala.concurrent.duration._
import com.opencagedata.geocoder.OpenCageClient
/**
* A simple sample app to show how to use the client.
*/
object OpenCageClientForwardDemoApp {
def main(args: Array[String]): Unit = {
val parser = new scopt.OptionParser[Config]("OpenCageClientApp") {
head("OpenCageClientApp", "0.1")
opt[String]('q', "query").required().action( (q, c) =>
c.copy(query = q) ).text("the query you want issue")
opt[String]('k', "key").required().action( (k, c) =>
c.copy(key = k) ).text("your authentication key")
}
parser.parse(args, Config()) match {
case Some(config) =>
val client = new OpenCageClient(config.key)
val responseFuture = client.forwardGeocode(config.query)
val response = Await.result(responseFuture, 5.seconds)
println(response)
client.close()
case None => System.exit(1)
}
}
}
case class Config(query: String = "", key: String = "")
and don't forget to add Scopt
and OpenCage
dependencies with desired versions to the newly created build.sbt
libraryDependencies ++= Seq(
"com.github.scopt" %% "scopt" % "X.Y.Z",
"com.opengagedata" %% "scala-opencage-geocoder" % "X.Y.Z"
)
Using Scala 2.12.8
, use "scopt" % "4.1.0"
, and "scala-opencage-geocoder" % "1.1.1"
Then if you'd like to try the sample application included with this library, just run (e.g. forward geocoding the Brandenburg Gate):
sbt 'runMain runMain com.github.nmdguerreiro.opencage.geocoder.OpenCageClientForwardDemoApp -q "Brandenburg Gate" -k <your key>'
The client can be configured by passing one or more of the optional constructor arguments:
val client = new OpenCageClient(authKey: String,
scheme: Scheme = OpenCageClient.defaultScheme,
hostname: String = OpenCageClient.defaultHostname,
port: Int = OpenCageClient.defaultPort,
executionContext: ExecutionContext = ExecutionContext.global,
backend: SttpBackend[Future, Nothing] = OpenCageClient.defaultBackend)
scheme
- Allows you to specify if the request is to be made over HTTP or HTTPS (for testing purposes, if you're mocking the API)hostname
- Allows you to specify the hostname (for testing purposes, if you're mocking the API)port
- Allows you to specify the port (for testing purposes, if you're mocking the API)executionContext
- Allows you to specify the thread pool to be used for processing the responsesbackend
- Allows you to specify a different backend, or to customise the default one.The client uses the async-http-client backend from sttp by default.
However, you can configure async-http-client
by using your own config object as per below (e.g. setting maximum number of connections in the pool):
val config = new DefaultAsyncHttpClientConfig.Builder().setMaxConnections(10).build()
val backend = AsyncHttpClientFutureBackend.withConfig(config)
Or by specifying options, such as a connection timeout or proxy by using custom backend options directly via sttp
:
val options = SttpBackendOptions(connectionTimeout, proxy)
val backend = AsyncHttpClientFutureBackend(options)
Finally, you can also implement your own sttp
backend, as long as it's asynchronous.
Make sure you have your file keys pubring.asc
and secring.asc
in ~/.sbt/gpg/
.
If those files are a new pair of key files, you have to publish to Sonatype's keyserver with
sbt pgp-cmd <key id> hkp://pool.sks-keyservers.net
Then just follow standard procedure using sbt-sonatype plugin.
Remember to create file ~/.sbt/opencage_sonatype_credentials
with contents
realm=Sonatype Nexus Repository Manager
host=oss.sonatype.org
user=<Sonatype username>
password=<Sonatype password>
Then from the console issue
$ sbt
sbt:scala-opencage-geocoder> +publishSigned
sbt:scala-opencage-geocoder> sonatypeRelease
This code was originally written by Nuno Guerreiro who later transfered it to the OpenCage organisation. Thank you Nuno!