Skip to content

Commit

Permalink
added api key
Browse files Browse the repository at this point in the history
  • Loading branch information
javisantana committed May 16, 2012
1 parent fc68a58 commit 1c6a891
Show file tree
Hide file tree
Showing 13 changed files with 266 additions and 18 deletions.
1 change: 1 addition & 0 deletions .gitignore
@@ -1,3 +1,4 @@

*.class
bin
test/com/cartodb/Secret.java
39 changes: 27 additions & 12 deletions README.md
Expand Up @@ -6,32 +6,47 @@ send queries to CartoDB and get a JSON string as response.

##Usage

//Access to your public table
CartoDBClientIF cartoDBCLient= new CartoDBClient("youraccount");
System.out.println(cartoDBCLient.executeQuery("SELECT * FROM yourtable LIMIT 1"));
With this library you have access to private and public tables. In order to access to public tables you do not need to be authenticated
but if you want to read or write data to a private table or write data to a public table you need to.

CartoDB provices two ways to auth, oauth or api key, please read [CartoDB Authentication documentation](http://developers.cartodb.com/documentation/cartodb-apis.html#authentication) for detailed info on this topic.


### Using oAuth

//Access to your private table or update your table
CartoDBClientIF cartoDBCLient= new SecuredCartoDBClient("youraccount","yourpassword","consumerKey","consumerSecret");
System.out.println(cartoDBCLient.executeQuery("UPDATE yourtable SET yourvalue = 'test' WHERE yourid = 1"));

###Use resulting JSON as Java object
To transform your JSON string into real Java object, you can use a combination of [json.org](http://json.org/java/) and [Apache Bean utils](http://commons.apache.org/beanutils/).
You could also use [Jackson`s ObjectMapper](http://jackson.codehaus.org/), which is easier to use but a little bit slower on very simple JSON string (based on my own test).
Here is an example using Jackson's ObjectMapper:
### Using API key

//Access to your private table or update your table using the api key
CartoDBClientIF cartoDBCLient= new ApiKeyCartoDBClient("youraccount", YOUR_API_KEY);
System.out.println(cartoDBCLient.executeQuery("UPDATE yourtable SET yourvalue = 'test' WHERE yourid = 1"));

### Access to Public tables (no auth required)

//Access to your public table
CartoDBClientIF cartoDBCLient= new CartoDBClient("youraccount");
System.out.println(cartoDBCLient.executeQuery("SELECT * FROM yourtable LIMIT 1"));


### get results as java object

//this object is expensive to create so keep the reference
ObjectMapper jacksonMapper = new ObjectMapper();
CartoDBResponse<OccurrenceModel> response = jacksonMapper.readValue(json, new TypeReference<CartoDBResponse<OccurrenceModel>>(){});
executeQuery method returns the raw json response. If you want to retrieve the json already parsed into a java object you can use request method, see next example:

My CartoDBResponse is now filled with a List of OccurrenceModel object, which represents the result of my query. Note that OccurrenceModel need to follow the JavaBean specifications. TypeReference is only a Wrapper to help the ObjectMapper manage Java Generics.
// get rows as a Map
CartoDBResponse<Map<String, Object>> res = cartoDBCLient.request("select * from mytable limit 1");
System.out.print(res.getTotal_rows(), 1);
System.out.print(res.getRows().get(0).get("cartodb_id"));

##Dependencies
_Included in lib folder_

* [Scribe](https://github.com/fernandezpablo85/scribe-java)
* [Apache commons codec](http://commons.apache.org/codec/)
* [Apache commons IO](http://commons.apache.org/io/)
* [Jackson`s ObjectMapper](http://jackson.codehaus.org/)

##TODO
* Include error JSON on HTTP response 400.
* executeQuery(sql) with a List of Java beans as return type
Binary file added lib/jackson-annotations-2.0.2.jar
Binary file not shown.
Binary file added lib/jackson-core-2.0.2.jar
Binary file not shown.
Binary file added lib/jackson-databind-2.0.2.jar
Binary file not shown.
36 changes: 34 additions & 2 deletions src/com/cartodb/CartoDBClientIF.java
@@ -1,17 +1,49 @@
package com.cartodb;

import java.io.IOException;

import com.cartodb.model.CartoDBResponse;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;


/**
* Interface for CartoDB client implementation
* @author canadensys
* @param <T>
*
*/
public interface CartoDBClientIF {
public abstract class CartoDBClientIF {

ObjectMapper jsonMapper = new ObjectMapper();
/**
* Executes a query on the CartoDB server
* @param sqlQuery do not URL encode the query, this function will do it.
* @return response as JSON string or null if the query cannot be completed
* @throws CartoDBException
*/
public String executeQuery(String sqlQuery);
public abstract String executeQuery(String sqlQuery) throws CartoDBException;

/**
* return a CartoDBResponse object with the response json parsed
* @param <T> object to map the columns
* @param sqlQuery
* @return CartoDBResponse object
* @throws CartoDBException
*/
public <T> CartoDBResponse<T> request(String sqlQuery) throws CartoDBException {
String json = executeQuery(sqlQuery);
CartoDBResponse<T> response;
try {
response = jsonMapper.readValue(json, new TypeReference<CartoDBResponse<T>>(){});

} catch (Exception e) {
throw new CartoDBException(e.getMessage());
}
return response;
}


}
9 changes: 9 additions & 0 deletions src/com/cartodb/CartoDBException.java
@@ -0,0 +1,9 @@
package com.cartodb;

public class CartoDBException extends Exception {

public CartoDBException(String msg) {
super(msg);
}

}
114 changes: 114 additions & 0 deletions src/com/cartodb/impl/ApiKeyCartoDBClient.java
@@ -0,0 +1,114 @@
package com.cartodb.impl;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;

import javax.smartcardio.CardException;

import org.apache.commons.io.IOUtils;
import org.scribe.builder.ServiceBuilder;
import org.scribe.model.OAuthRequest;
import org.scribe.model.Response;
import org.scribe.model.Token;
import org.scribe.model.Verb;
import org.scribe.oauth.OAuthService;

import com.cartodb.CartoDBAPI;
import com.cartodb.CartoDBClientIF;
import com.cartodb.CartoDBException;

/**
* CartoDB client implementation to access protected resources on CartoDB using OAuth.
* You can perform any SQL queries so please, be careful.
* @author canadensys
*
*/
public class ApiKeyCartoDBClient extends CartoDBClientIF {

private static final String DEFAULT_API_VERSION = "1";
private static final String ENCODING = "UTF-8";

private static final String SQL_API_BASE_URL = "http://%s.cartodb.com/api/v%s/sql/";

private String user;
private String apiVersion = DEFAULT_API_VERSION;
private String apiURL = null;

/**
* aki key, it can be found in your dashboard
*/
private String apiKey;


/**
* Default constructor
*/
public ApiKeyCartoDBClient(){}

/**
* After this constructor, the object is ready to use.
* @param user
* @param apiKey api provided by cartodb to access to secured resources
* @throws CartoDBException
*/
public ApiKeyCartoDBClient(String user, String apiKey) throws CartoDBException {
this.user = user;
this.apiKey = apiKey;
if(this.apiKey == null || this.apiKey.length() == 0) {
throw new CartoDBException("provided API key is not valid");
}
init();
}

/**
* Initialization method for a regular CartoDB client.
* You only need it if you're using the default constructor.
*/
public void init(){
apiURL = String.format(SQL_API_BASE_URL, user, apiVersion);
}

/**
* Send a sqlQuery to the CartoDB server.
* The query will be sent in a URL parameter of a GET so, you should avoid very large query string.
* @param sqlQuery
* @throws CartoDBException
*/
public String executeQuery(String sqlQuery) throws CartoDBException {
String json = null;

if(apiURL == null){
System.out.println("Error : uninitialized " + getClass().getName());
return null;
}

try {
sqlQuery = URLEncoder.encode(sqlQuery, ENCODING);
String params = "q=" + sqlQuery + "&api_key=" + this.apiKey;
json = IOUtils.toString(new URL(apiURL + "?" + params), ENCODING);
} catch (MalformedURLException e) {
throw new CartoDBException("Could not get URL " + apiURL + sqlQuery);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}catch (IOException e) {
throw new CartoDBException("Could not execute " + sqlQuery + " on CartoDB : ");
}
return json;
}

public void setUser(String user){
this.user = user;
}

/**
* Set the API version to use.
* @param apiVersion number part only as String
*/
public void setApiVersion(String apiVersion){
this.apiVersion = apiVersion;
}

}
5 changes: 3 additions & 2 deletions src/com/cartodb/impl/CartoDBClient.java
Expand Up @@ -9,14 +9,15 @@
import org.apache.commons.io.IOUtils;

import com.cartodb.CartoDBClientIF;
import com.cartodb.CartoDBException;

/**
* CartoDB client implementation to access public resources. You can only send SELECT queries to public
* resources.
* @author canadensys
*
*/
public class CartoDBClient implements CartoDBClientIF{
public class CartoDBClient extends CartoDBClientIF{

private static final String DEFAULT_API_VERSION = "1";
private static final String ENCODING = "UTF-8";
Expand Down Expand Up @@ -66,7 +67,7 @@ public void init(){
* @param sqlQuery
*/
@Override
public String executeQuery(String sqlQuery){
public String executeQuery(String sqlQuery) throws CartoDBException {
String json = null;

if(apiURL == null){
Expand Down
5 changes: 3 additions & 2 deletions src/com/cartodb/impl/SecuredCartoDBClient.java
Expand Up @@ -9,14 +9,15 @@

import com.cartodb.CartoDBAPI;
import com.cartodb.CartoDBClientIF;
import com.cartodb.CartoDBException;

/**
* CartoDB client implementation to access protected resources on CartoDB using OAuth.
* You can perform any SQL queries so please, be careful.
* @author canadensys
*
*/
public class SecuredCartoDBClient implements CartoDBClientIF{
public class SecuredCartoDBClient extends CartoDBClientIF{

private static final String DEFAULT_API_VERSION = "1";
private static final String SQL_API_BASE_URL = "https://%s.cartodb.com/api/v%s/sql";
Expand Down Expand Up @@ -72,7 +73,7 @@ public void init(){
* @param sqlQuery
*/
@Override
public String executeQuery(String sqlQuery){
public String executeQuery(String sqlQuery) throws CartoDBException {
String json = null;
if(oAuthService == null){
System.out.println("Error : uninitialized " + getClass().getName());
Expand Down
17 changes: 17 additions & 0 deletions test/com/cartodb/CartoDBApiKeyClient.java
@@ -0,0 +1,17 @@
package com.cartodb;

import org.junit.Before;

import com.cartodb.impl.ApiKeyCartoDBClient;
import com.cartodb.impl.SecuredCartoDBClient;

public class CartoDBApiKeyClient extends CartoDBTestClient {




@Before
public void setUp() throws Exception {
this.cartoDBCLient = new ApiKeyCartoDBClient(Secret.user, Secret.API_KEY);
}
}
15 changes: 15 additions & 0 deletions test/com/cartodb/CartoDBSecureClientTest.java
@@ -0,0 +1,15 @@
package com.cartodb;

import org.junit.Before;

import com.cartodb.impl.SecuredCartoDBClient;

public class CartoDBSecureClientTest extends CartoDBTestClient {



@Before
public void setUp() throws Exception {
this.cartoDBCLient = new SecuredCartoDBClient(Secret.user, Secret.password, Secret.CONSUMER_KEY, Secret.CONSUMER_SECRET);
}
}
43 changes: 43 additions & 0 deletions test/com/cartodb/CartoDBTestClient.java
@@ -0,0 +1,43 @@
package com.cartodb;

import java.util.Map;

import org.junit.Ignore;
import org.junit.Test;

import com.cartodb.model.CartoDBResponse;

import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;

/**
* base class for client tests
* @author javi
*
*/
@Ignore
public class CartoDBTestClient {

CartoDBClientIF cartoDBCLient;

/**
* wrong sql should raise a CartoDBException
* @throws CartoDBException
*/
@Test(expected=CartoDBException.class)
public void testWrongSql() throws CartoDBException {
CartoDBResponse<String> res = cartoDBCLient.request("select * from asdasdasdas123asd limit 1");
assertEquals(res.getTotal_rows(), 1);
}

@Test
public void testClientSQL() throws CartoDBException {

CartoDBResponse<Map<String, Object>> res = cartoDBCLient.request("select * from " + Secret.EXISTING_TABLE_WITH_DATA + " limit 1");
assertEquals(res.getTotal_rows(), 1);
assertTrue((Integer)res.getRows().get(0).get("cartodb_id") > 0);


}

}

0 comments on commit 1c6a891

Please sign in to comment.