Skip to content
This repository was archived by the owner on Mar 31, 2025. It is now read-only.

Commit 85c1cc1

Browse files
authored
Merge pull request #4 from Sybit-Education/develop
Develop
2 parents 7bb226a + 79ccd51 commit 85c1cc1

15 files changed

Lines changed: 371 additions & 68 deletions

File tree

README.md

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,18 @@ The API supports environment variable `http_proxy`. If the variable is set, it i
4747

4848
If `endpointUrl` contains `localhost` or `127.0.0.1` proxy settings are ignored automatically.
4949

50-
## Logging
50+
### Logging
5151

52-
The Simple Logging Facade for Java [https://www.slf4j.org/](SLF4J) serves as a simple facade or abstraction for various logging frameworks (e.g. java.util.logging, logback, log4j) allowing the end user to plug in the desired logging framework at deployment time.
52+
The Simple Logging Facade for Java [https://www.slf4j.org/](SLF4J) serves as a simple facade or abstraction
53+
for various logging frameworks (e.g. java.util.logging, logback, log4j) allowing the end user to plug in the desired
54+
logging framework at deployment time.
5355

56+
### Request Limits
57+
The API of Airtable itself is limited to 5 requests per second. If you exceed this rate, you will receive a 429 status code and will
58+
need to wait 30 seconds before subsequent requests will succeed.
5459

55-
## Access Base
5660

57-
## Access Table
58-
59-
## CRUD-Operations on table items
61+
## CRUD-Operations on Table Records
6062

6163
## Select
6264
Select List of items from table:
@@ -87,15 +89,29 @@ Table<Actor> actorTable = base.table("Actors", Actor.class);
8789
Actor actor = actorTable.find("rec514228ed76ced1");
8890
```
8991

92+
## Destroy
93+
Use Destroy to delete a specific records of table:
94+
95+
+ `table(name).destroy(String id)`: delete record with `id` of table `name`
96+
97+
### Example
98+
```Java
99+
// detailed Example see TableDestroyTest.java
100+
Base base = airtable.base(AIRTABLE_BASE);
101+
Table<Actor> actorTable = base.table("Actors", Actor.class);
102+
actorTable.destroy("recapJ3Js8AEwt0Bf");
103+
```
104+
90105
## Annotations
91106

92-
Use the Gson Annotation @SerializedName to annotate Names which contain - or an emtpy Charakter.
107+
Use the Gson Annotation `@SerializedName` to annotate Names which contain `-` or emtpy characters.
93108

94109
### Example
95110
```Java
96111

97112
import com.google.gson.annotations.SerializedName;
98113

114+
//Column in Airtable is named "First- & Lastname", which is mapped to field "name".
99115
@SerializedName("First- & Lastname")
100116
private String name;
101117
```
@@ -104,9 +120,9 @@ Use the Gson Annotation @SerializedName to annotate Names which contain - or an
104120
+ [x] Airtable Configure
105121
+ [x] configuration of `proxy`
106122
+ [x] configuration of `AIRTABLE_API_KEY` & `AIRTABLE_BASE`
107-
+ [ ] configuration of `requestTimeout`
123+
+ [x] configuration of `requestTimeout`
108124

109-
+ [x] Select
125+
+ [x] Select Records
110126
+ [x] SelectAll
111127
+ [x] Queries (`maxRecords`, `sort` & `view` )
112128
+ [ ] Support of `filterByFormula`
@@ -116,7 +132,7 @@ Use the Gson Annotation @SerializedName to annotate Names which contain - or an
116132

117133
+ [ ] Create Record
118134
+ [ ] Update Record
119-
+ [ ] Delete Record
135+
+ [x] Delete Record
120136
+ [ ] Replace Record
121137
+ General requirements
122138
+ [ ] Automatic ObjectMapping
@@ -151,5 +167,3 @@ We use following libraries:
151167
# License
152168

153169
MIT License, see [LICENSE](LICENSE)
154-
155-

src/main/java/com/sybit/airtable/Airtable.java

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99

1010
import com.mashape.unirest.http.Unirest;
11+
import com.sybit.airtable.converter.ListConverter;
12+
import com.sybit.airtable.converter.MapConverter;
1113
import com.sybit.airtable.exception.AirtableException;
1214
import com.sybit.airtable.vo.Attachment;
1315
import com.sybit.airtable.vo.Thumbnail;
@@ -42,12 +44,11 @@
4244
public class Airtable {
4345

4446
private static final Logger LOG = LoggerFactory.getLogger( Airtable.class );
45-
private static final String ENDPOINT_URL = "https://api.airtable.com/v0";
47+
4648
private static final String AIRTABLE_API_KEY = "AIRTABLE_API_KEY";
4749
private static final String AIRTABLE_BASE = "AIRTABLE_BASE";
4850

49-
private String endpointUrl;
50-
private String apiKey;
51+
private Configuration config;
5152

5253
/**
5354
* Configure, <code>AIRTABLE_API_KEY</code> passed by Java property, enviroment variable
@@ -84,29 +85,32 @@ public Airtable configure() throws AirtableException {
8485
*/
8586
@SuppressWarnings("WeakerAccess")
8687
public Airtable configure(String apiKey) throws AirtableException {
87-
return configure(apiKey, ENDPOINT_URL);
88+
return configure(new Configuration(apiKey, Configuration.ENDPOINT_URL));
8889
}
8990

9091
/**
9192
*
92-
* @param apiKey
93-
* @param endpointUrl
93+
* @param config
9494
* @return
9595
* @throws com.sybit.airtable.exception.AirtableException Missing API-Key or Endpoint
9696
*/
9797
@SuppressWarnings("WeakerAccess")
98-
public Airtable configure(String apiKey, String endpointUrl) throws AirtableException {
99-
if(apiKey == null) {
98+
public Airtable configure(Configuration config) throws AirtableException {
99+
if(config.getApiKey() == null) {
100100
throw new AirtableException("Missing Airtable API-Key");
101101
}
102-
if(endpointUrl == null) {
102+
if(config.getEndpointUrl() == null) {
103103
throw new AirtableException("Missing endpointUrl");
104104
}
105105

106-
this.apiKey = apiKey;
107-
this.endpointUrl = endpointUrl;
106+
this.config = config;
108107

109-
setProxy(endpointUrl);
108+
if(config.getTimeout() != null) {
109+
LOG.info("Set connection timeout to: " + config.getTimeout() + "ms.");
110+
Unirest.setTimeouts(config.getTimeout(), config.getTimeout());
111+
}
112+
113+
setProxy(config.getEndpointUrl());
110114

111115
// Only one time
112116
Unirest.setObjectMapper(new GsonObjectMapper());
@@ -188,20 +192,29 @@ public Base base(String base) throws AirtableException {
188192
return b;
189193
}
190194

195+
public Configuration getConfig() {
196+
return config;
197+
}
198+
199+
public void setConfig(Configuration config) {
200+
this.config = config;
201+
setProxy(config.getEndpointUrl());
202+
}
203+
191204
/**
192205
*
193206
* @return
194207
*/
195208
public String endpointUrl() {
196-
return endpointUrl;
209+
return this.config.getEndpointUrl();
197210
}
198211

199212
/**
200213
*
201214
* @return
202215
*/
203216
public String apiKey() {
204-
return apiKey;
217+
return this.config.getApiKey();
205218
}
206219

207220
/**
@@ -233,7 +246,7 @@ private String getCredentialProperty(String key) {
233246
}
234247

235248
public void setEndpointUrl(String endpointUrl) {
236-
this.endpointUrl = endpointUrl;
249+
this.config.setEndpointUrl(endpointUrl);
237250
setProxy(endpointUrl);
238251
}
239252
}

src/main/java/com/sybit/airtable/Base.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public Base(String base, Airtable airtable) {
5353
* Set Airtable object as parent.
5454
* @param parent the base Airtable object.
5555
*/
56-
protected void setParent(Airtable parent) {
56+
void setParent(Airtable parent) {
5757
this.parent = parent;
5858
}
5959

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* The MIT License (MIT)
3+
* Copyright (c) 2017 Sybit GmbH
4+
*
5+
* Permission is hereby granted, free of charge, to any person obtaining a copy
6+
*/
7+
package com.sybit.airtable;
8+
9+
/**
10+
* Configuration settings for Airtable.
11+
* Used by class <code>Airtable</code> to configure basic settings.
12+
*/
13+
public class Configuration {
14+
15+
public static final String ENDPOINT_URL = "https://api.airtable.com/v0";
16+
17+
private String endpointUrl;
18+
private String apiKey;
19+
private Long timeout;
20+
21+
/**
22+
* Configure API using given API Key and default endpoint.
23+
*
24+
* @param apiKey
25+
*/
26+
public Configuration(String apiKey) {
27+
this(apiKey, ENDPOINT_URL);
28+
29+
}
30+
/**
31+
* Configure API using given API Key and default endpointURL.
32+
*
33+
* @param apiKey
34+
* @param endpointUrl
35+
*/
36+
public Configuration(String apiKey, String endpointUrl) {
37+
this.apiKey = apiKey;
38+
this.endpointUrl = endpointUrl;
39+
}
40+
41+
public String getEndpointUrl() {
42+
return endpointUrl;
43+
}
44+
45+
public void setEndpointUrl(String endpointUrl) {
46+
this.endpointUrl = endpointUrl;
47+
}
48+
49+
public String getApiKey() {
50+
return apiKey;
51+
}
52+
53+
public void setApiKey(String apiKey) {
54+
this.apiKey = apiKey;
55+
}
56+
57+
/**
58+
* Get connection timeout.
59+
* @return
60+
*/
61+
public Long getTimeout() {
62+
return timeout;
63+
}
64+
65+
/**
66+
* Set connection timeout.
67+
* @param timeout
68+
*/
69+
public void setTimeout(Long timeout) {
70+
this.timeout = timeout;
71+
}
72+
}

src/main/java/com/sybit/airtable/GsonObjectMapper.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*
1616
* @author fzr
1717
*/
18-
class GsonObjectMapper implements ObjectMapper{
18+
class GsonObjectMapper implements ObjectMapper {
1919
private static final Logger LOG = Logger.getLogger( GsonObjectMapper.class.getName() );
2020
private final Gson gson;
2121

@@ -25,11 +25,12 @@ public GsonObjectMapper() {
2525
}
2626

2727
public <T> T readValue(String value, Class<T> valueType) {
28-
LOG.log(Level.INFO, "readValue: \n" + value);
28+
LOG.log(Level.FINE, "readValue: \n" + value);
2929
return gson.fromJson(value, valueType);
3030
}
3131

3232
public String writeValue(Object value) {
33+
LOG.log(Level.FINE, "writeValue: \n" + value);
3334
return gson.toJson(value);
3435
}
3536

src/main/java/com/sybit/airtable/Query.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,10 @@ public interface Query {
2929
List<Sort> getSort();
3030

3131
/**
32+
* Define a filter formula.
3233
*
33-
* @return
34+
* see https://support.airtable.com/hc/en-us/articles/203255215-Formula-Field-Reference
35+
* @return get the filter formula.
3436
*/
3537
String filterByFormula();
3638
}

src/main/java/com/sybit/airtable/Table.java

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import com.mashape.unirest.request.GetRequest;
1414
import com.sybit.airtable.exception.AirtableException;
1515
import com.sybit.airtable.exception.HttpResponseExceptionHandler;
16+
import com.sybit.airtable.vo.Delete;
1617
import com.sybit.airtable.vo.RecordItem;
1718
import com.sybit.airtable.vo.Records;
1819
import org.apache.commons.beanutils.BeanUtils;
@@ -110,7 +111,7 @@ public String filterByFormula() {
110111
* @throws HttpResponseException
111112
*/
112113
@SuppressWarnings("WeakerAccess")
113-
public List<T> select(Query query) throws AirtableException, HttpResponseException {
114+
public List<T> select(Query query) throws AirtableException {
114115
HttpResponse<Records> response;
115116
try {
116117
GetRequest request = Unirest.get(getTableEndpointUrl())
@@ -272,7 +273,7 @@ private List<T> getList(HttpResponse<Records> response) {
272273
* @return searched record.
273274
* @throws AirtableException
274275
*/
275-
public T find(String id) throws AirtableException, HttpResponseException {
276+
public T find(String id) throws AirtableException {
276277

277278
RecordItem body = null;
278279

@@ -316,10 +317,38 @@ public T replace(T item) {
316317

317318
throw new UnsupportedOperationException("not yet implemented");
318319
}
320+
321+
/**
322+
* Delete Record by given id
323+
*
324+
* @param id
325+
* @throws AirtableException
326+
*/
319327

320-
public T destroy(T item) {
328+
public void destroy(String id) throws AirtableException {
329+
330+
Delete body = null;
321331

322-
throw new UnsupportedOperationException("not yet implemented");
332+
HttpResponse<Delete> response;
333+
try {
334+
response = Unirest.delete(getTableEndpointUrl() + "/" + id)
335+
.header("accept", "application/json")
336+
.header("Authorization", getBearerToken())
337+
.asObject(Delete.class);
338+
} catch (UnirestException e) {
339+
throw new AirtableException(e);
340+
}
341+
int code = response.getStatus();
342+
343+
if(200 == code) {
344+
body = response.getBody();
345+
} else {
346+
HttpResponseExceptionHandler.onResponse(response);
347+
}
348+
349+
if(!body.isDeleted()){
350+
throw new AirtableException("Record id: "+body.getId()+" could not be deleted.");
351+
}
323352
}
324353

325354
/**
@@ -423,7 +452,7 @@ private void setProperty(T retval, String key, Object value) throws IllegalAcces
423452
private String key2property(String key) {
424453

425454
if(key.contains(" ") || key.contains("-") ) {
426-
LOG.warn( "Annotate special characters using @SerializedName for property: [" + key + "]");
455+
LOG.warn( "Annotate columns having special characters by using @SerializedName for property: [" + key + "]");
427456
}
428457
String property = key.trim();
429458
property = property.substring(0,1).toLowerCase() + property.substring(1, property.length());

0 commit comments

Comments
 (0)