The Datafiniti API is owned and maintained by Datafinity See datafiniti-api.readme.io
This is an open source wrapper for that API, maintained by Datlinq
- Business Data
- Product Data
- Property Data
Add to your build.sbt
libraryDependencies += "com.datlinq" %% "scalafiniti" % "0.3.4"
Then add import statement
import com.datlinq.datafiniti._
import com.datlinq.datafiniti.config.DatafinitiAPIFormats._
import com.datlinq.datafiniti.config.DatafinitiAPIViewsV4._
import com.datlinq.datafiniti.config.DatafinitiAPITypes._
Create an APIv4 object
val email = "..."
val password = "..."
val apiv4 = DatafinitiAPIv4(email, password)
Now query the API
Errors in the future or non-200 results are captured in DatafinitiErrors
Otherwise the result is parsed with json4s (even CSV requests, that return json with as CSV field)
The async calls return an DatafinitiFuture[T] which are EitherT[Future,DatafinitiError,JValue]] (see cats library)
This makes the Eithers in Futures composable in for comprehensions and such
val response:DatafinitiFuture[JValue] = apiv4.search(
SearchRequestV4(
query = "categories:hotels",
view_name = BusinessesBasic,
records = Some(1),
format = JSON,
download = false,
view = None
))
To get an individual record from Datafiniti there is a specific call recordById
The main difference is that it's a Restful GET request with id in url.
The SDK syntax is similar to the query, but simpler.
Only a id as String
and a specific APIType
are required
val response:DatafinitiFuture[JValue] = apiv4.recordById("xxxxxxxxx", Businesses)
The Download flow contains of multiple API calls first triggering the download, then redirect to polling API call untill the download is marked as COMPLETED afterwards redirecting to a similar API call to fetch the download URL's
The method downloadLinks
returns a List of Strings wrapped in a DatafinitiFuture.
val response:DatafinitiFuture[List[String]] = apiv4.downloadLinks(
SearchRequestV4(
query = """categories:hotels AND city:"Capelle aan den IJssel"""",
view_name = BusinessesBasic,
records = Some(1),
format = JSON,
download = true,
view = None
))
or download all files directly to a stream. Pass an outputstream to append lines, beware that resulting file may have records be out of order if there are multiple download files in the response, to prevent this set sequential to true (will be slower). The returned integer contains the total count of all (or limited by numberOfRecords) imported records
val response:DatafinitiFuture[Int] = apiv4.download(
SearchRequestV4("""categories:hotels AND city:Rotterdam""", BusinessesBasic, numRecords, JSON), sequential = true)(stream)
User information, including access rights and remaining requests are accessed by the
userInfo, returning the entire Json (or sub json if string was passed)
val et: DatafinitiFuture[JValue] = apiv4.userInfo()
and userInfoField, returning a specificly extracted value from user info (like "available_downloads")
val et: DatafinitiFuture[Option[Long]] = apiv4.userInfoField("available_downloads")
JSON
CSV
(basic query still returns json result, but with one field filled with CSV data)
BusinessesDefault
- nullBusinessesAllFlatMenus
- business_flat_menus"BusinessesAllFlatReviews
- business_flat_reviews"BusinessesAllNested
- business_all_nested"BusinessesNoReviews
- business_no_reviews"BusinessesBasic
- business_basic"ProductsDefault
- nullProductsAllNested
- product_all_nested"ProductsFlatPrices
- product_flat_prices"ProductsFlatReviews
- product_flat_reviews"PropertiesDefault
- nullPropertiesFlatPrices
- property_flat_prices"PropertiesFlatReviews
- property_flat_reviews"
BusinessesAll
- businesses_allBusinessesAllMenusFlat
- businesses_all_menusFlatBusinessesAllNested
- businesses_all_nestedBusinessesAllNestedNoReviews
- businesses_all_nested_no_reviewsBusinessesAllBasic
- businesses_basicProductsAll
- products_allProductsKeysSourceURLs
- products_keysSourceURLsProductsMultiValuedFieldsNested
- products_multiValuedFieldsNestedProductsPricesFlat
- products_pricesFlatProductsReviewsFlat
- products_reviewsFlat
- Tom Lous (@tomlous)
import com.datlinq.datafiniti.config.DatafinitiAPIFormats._
import com.datlinq.datafiniti.config.DatafinitiAPITypes._
import com.datlinq.datafiniti.config.DatafinitiAPIViewsV4._
import com.datlinq.datafiniti.request.SearchRequest.SearchRequestV4
import org.json4s.JsonAST.JNothing
import scala.concurrent.Await
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.Duration
val email = "...."
val password = "...."
val apiv4 = DatafinitiAPIv4()
// query
val futureEither = apiv4.search(
SearchRequestV4("""categories:restaurant AND city:Bergschenhoek""", BusinessesAllNested, Some(10), JSON))
val result = Await.result(futureEither.value, Duration.Inf)
val json = result.right.getOrElse(JNothing)
// recordById
val futureEither2 = apiv4.recordById("AWEF3R5B3-Khe5l_drZz", Businesses)
val result2 = Await.result(futureEither2.value, Duration.Inf)
val json2 = result2.right.getOrElse(JNothing)
// download links
val futureEither3 = apiv4.downloadLinks(
SearchRequestV4("""categories:restaurant AND city:Lansingerland""", BusinessesAllNested)
)
val result3 = Await.result(futureEither3.value, Duration.Inf)
val links = result3.right.getOrElse(Nil)
// download
val stream = new FileOutputStream("/tmp/output.json")
val futureEither4 = apiv4.download(
SearchRequestV4(
view_name = BusinessesAllNested,
query = """categories:restaurant AND city:"Berkel en Rodenrijs"""",
format = JSON,
num_records = None
),
sequential = false
)(stream)
val result4 = Await.result(futureEither4.value, Duration.Inf)
stream.close()
The code was build for scala 2.11, 2.12 and for version v3 & v4 of the Dafaniti API