PC + WiFi | Mobile + WiFi | Mobile + LTE | Mobile + HSDPA+ | Mobile + 2G | |
---|---|---|---|---|---|
min | 0.993 | 2 | 15 | 42 | 203 |
avg | 3.435 | 19 | 90 | 60 | 227 |
max | 30.678 | 460 | 811 | 956 | 2000 |
stddev | 2.22 | 17 | x | 55 | 84 |
down | 139.90 | 18.57 | 14.47 | 5.73 | 0.08 |
up | 86.19 | 18.23 | 5.73 | 3.68 | 0.1 |
GET /users/123
{
"name": "John Doe",
"age": 25,
"links": [
{
"rel": "self",
"href": "/users/123"
},
{
"rel": "account",
"href": "/accounts/987"
},
{
"rel": "address",
"href": "/addresses/555"
}
]
}
GET /addresses/555
{
"street": "Sesame",
"no": 25,
"zipCode": "12-321",
"state": "NY",
"country": "US"
}
GET /users/123
{
"name": "John Doe",
"age": 25,
"country": "US"
}
GET /users/123?fields=[name,age,address[country]]
{
"name": "John Doe",
"age": 25,
"country": "US"
}
Connection: Keep-Alive
Complete model
{
"person": {
"id": 12345,
"firstName": "John",
"lastName": "Doe",
"age": 25,
"phones": {
"home": "800-123-4567",
"work": "888-555-0000",
"cell": "877-123-1234"
},
"email": [
"jd@example.com",
"jd@example.org"
],
"dateOfBirth": "1980-01-02T00:00:00.000Z",
"registered": true,
"emergencyContacts": [
{
"name": "",
"phone": "",
"email": "",
"relationship": "spouse|parent|child|other"
}
],
"address": {
"street": "Sesame",
"no": 25,
"zipCode": "12-321",
"state": "NY",
"country": "US"
}
}
}
Trimmed model
{
"firstName": "John",
"lastName": "Doe",
"age": 25,
"country": "US"
}
Full: 222910 bytes GZIP: 32128 bytes (14%)
{
"people": [
{
"firstName": "Jason",
"lastName": "Page",
"username": "jasonp",
"isMale": true,
"phone": "142-808-3743",
"nid": "12252671714"
},
{
"firstName": "Nathaniel",
"lastName": "Chaney",
"username": "nchaney",
"isMale": true,
"phone": "481-659-731",
"nid": "55122958778"
},
{
"firstName": "Alexis",
"lastName": "Christensen",
"username": "alexisc",
"isMale": false,
"phone": "802-046-8689",
"nid": "13240667404"
},
{
"firstName": "Sophie",
"lastName": "Duke",
"username": "sophied",
"isMale": false,
"phone": "316-701-3331",
"nid": "96071009282"
},
{
"firstName": "Aria",
"lastName": "Wolf",
"username": "ariaw",
"isMale": false,
"phone": "682-172-2915",
"nid": "12231830224"
},
{
"firstName": "Sebastian",
"lastName": "Hogan",
"username": "sebastianh",
"isMale": true,
"phone": "096-033-8930",
"nid": "65082565494"
},
{
"firstName": "Austin",
"lastName": "Rice",
"username": "austinr",
"isMale": true,
"phone": "558-871-007",
"nid": "91102544132"
},
{
"firstName": "Elijah",
"lastName": "Savage",
"username": "esavage",
"isMale": true,
"phone": "009-900-8985",
"nid": "10301742394"
},
{
"firstName": "Colton",
"lastName": "Morris",
"username": "cmorris",
"isMale": true,
"phone": "029-957-8223",
"nid": "84062095076"
},
{
"firstName": "Juan",
"lastName": "Bass",
"username": "jbass",
"isMale": true,
"phone": "701-810-3457",
"nid": "10311068954"
},
{
"firstName": "Brody",
"lastName": "Reese",
"username": "breese",
"isMale": true,
"phone": "320-610-636",
"nid": "82112959596"
},
{
"firstName": "Stella",
"lastName": "Bernard",
"username": "sbernard",
"isMale": false,
"phone": "134-462-1924",
"nid": "03272935528"
},
{
"firstName": "Isaac",
"lastName": "Webb",
"username": "iwebb",
"isMale": true,
"phone": "136-000-422",
"nid": "10231649814"
},
{
"firstName": "Jackson",
"lastName": "Bryan",
"username": "jacksonb",
"isMale": true,
"phone": "629-900-7729",
"nid": "83071189716"
},
{
"firstName": "Liam",
"lastName": "Beard",
"username": "lbeard",
"isMale": true,
"phone": "327-639-010",
"nid": "86050552116"
},
{
"firstName": "Parker",
"lastName": "Duffy",
"username": "pduffy",
"isMale": true,
"phone": "484-829-6473",
"nid": "56122687578"
},
{
"firstName": "Lucy",
"lastName": "Moody",
"username": "lucym",
"isMale": false,
"phone": "723-670-5321",
"nid": "77051444320"
},
{
"firstName": "Aaliyah",
"lastName": "Leonard",
"username": "aleonard",
"isMale": false,
"phone": "005-293-048",
"nid": "08281195048"
},
{
"firstName": "Brody",
"lastName": "Norris",
"username": "brodyn",
"isMale": true,
"phone": "789-653-2217",
"nid": "58050880078"
},
{
"firstName": "Juan",
"lastName": "Valenzuela",
"username": "juanv",
"isMale": true,
"phone": "060-065-140",
"nid": "93052612612"
},
{
"firstName": "Jocelyn",
"lastName": "Collins",
"username": "jcollins",
"isMale": false,
"phone": "010-257-964",
"nid": "65083166064"
},
{
"firstName": "Bentley",
"lastName": "Welch",
"username": "bentleyw",
"isMale": true,
"phone": "068-620-269",
"nid": "09293076518"
}
]
}
Full: 48 bytes GZIP: 60 bytes (125%)
{
"firstName": "Arianna",
"lastName": "Mcknight"
}
GET /people/
{
"people": [
{
"firstName": "Jason",
"lastName": "Page",
"username": "jasonp",
"isMale": true,
"phone": "142-808-3743",
"nid": "12252671714"
},
{
"firstName": "Nathaniel",
"lastName": "Chaney",
"username": "nchaney",
"isMale": true,
"phone": "481-659-731",
"nid": "55122958778"
},
{
"firstName": "Alexis",
"lastName": "Christensen",
"username": "alexisc",
"isMale": false,
"phone": "802-046-8689",
"nid": "13240667404"
},
{
"firstName": "Sophie",
"lastName": "Duke",
"username": "sophied",
"isMale": false,
"phone": "316-701-3331",
"nid": "96071009282"
},
{
"firstName": "Aria",
"lastName": "Wolf",
"username": "ariaw",
"isMale": false,
"phone": "682-172-2915",
"nid": "12231830224"
},
{
"firstName": "Sebastian",
"lastName": "Hogan",
"username": "sebastianh",
"isMale": true,
"phone": "096-033-8930",
"nid": "65082565494"
},
{
"firstName": "Austin",
"lastName": "Rice",
"username": "austinr",
"isMale": true,
"phone": "558-871-007",
"nid": "91102544132"
},
{
"firstName": "Elijah",
"lastName": "Savage",
"username": "esavage",
"isMale": true,
"phone": "009-900-8985",
"nid": "10301742394"
},
{
"firstName": "Colton",
"lastName": "Morris",
"username": "cmorris",
"isMale": true,
"phone": "029-957-8223",
"nid": "84062095076"
},
{
"firstName": "Juan",
"lastName": "Bass",
"username": "jbass",
"isMale": true,
"phone": "701-810-3457",
"nid": "10311068954"
},
{
"firstName": "Brody",
"lastName": "Reese",
"username": "breese",
"isMale": true,
"phone": "320-610-636",
"nid": "82112959596"
},
{
"firstName": "Stella",
"lastName": "Bernard",
"username": "sbernard",
"isMale": false,
"phone": "134-462-1924",
"nid": "03272935528"
},
{
"firstName": "Isaac",
"lastName": "Webb",
"username": "iwebb",
"isMale": true,
"phone": "136-000-422",
"nid": "10231649814"
},
{
"firstName": "Jackson",
"lastName": "Bryan",
"username": "jacksonb",
"isMale": true,
"phone": "629-900-7729",
"nid": "83071189716"
},
{
"firstName": "Liam",
"lastName": "Beard",
"username": "lbeard",
"isMale": true,
"phone": "327-639-010",
"nid": "86050552116"
},
{
"firstName": "Parker",
"lastName": "Duffy",
"username": "pduffy",
"isMale": true,
"phone": "484-829-6473",
"nid": "56122687578"
},
{
"firstName": "Lucy",
"lastName": "Moody",
"username": "lucym",
"isMale": false,
"phone": "723-670-5321",
"nid": "77051444320"
},
{
"firstName": "Aaliyah",
"lastName": "Leonard",
"username": "aleonard",
"isMale": false,
"phone": "005-293-048",
"nid": "08281195048"
},
{
"firstName": "Brody",
"lastName": "Norris",
"username": "brodyn",
"isMale": true,
"phone": "789-653-2217",
"nid": "58050880078"
},
{
"firstName": "Juan",
"lastName": "Valenzuela",
"username": "juanv",
"isMale": true,
"phone": "060-065-140",
"nid": "93052612612"
},
{
"firstName": "Jocelyn",
"lastName": "Collins",
"username": "jcollins",
"isMale": false,
"phone": "010-257-964",
"nid": "65083166064"
},
{
"firstName": "Bentley",
"lastName": "Welch",
"username": "bentleyw",
"isMale": true,
"phone": "068-620-269",
"nid": "09293076518"
}
]
}
GET /people?fields=[firstName, lastName]
{
"people": [
{
"firstName": "Kennedy",
"lastName": "Cote"
},
{
"firstName": "Jocelyn",
"lastName": "Parsons"
},
{
"firstName": "Mia",
"lastName": "Key"
},
{
"firstName": "Jackson",
"lastName": "Whitney"
},
{
"firstName": "Nevaeh",
"lastName": "Torres"
},
{
"firstName": "Samuel",
"lastName": "Best"
},
{
"firstName": "Ellie",
"lastName": "Hooper"
},
{
"firstName": "Kevin",
"lastName": "White"
},
{
"firstName": "Xavier",
"lastName": "Wooten"
},
{
"firstName": "Naomi",
"lastName": "Chan"
},
{
"firstName": "Owen",
"lastName": "Ramsey"
},
{
"firstName": "Victoria",
"lastName": "Hunter"
},
{
"firstName": "Harper",
"lastName": "Boone"
},
{
"firstName": "Nicholas",
"lastName": "Mcknight"
},
{
"firstName": "Kaylee",
"lastName": "Stone"
},
{
"firstName": "Hudson",
"lastName": "Schultz"
},
{
"firstName": "Thomas",
"lastName": "Copeland"
},
{
"firstName": "Madeline",
"lastName": "Odom"
},
{
"firstName": "Colton",
"lastName": "Humphrey"
},
{
"firstName": "Alexis",
"lastName": "Chandler"
}
]
}
PLAIN 171120 bytes GZIP 30855 bytes
Grayson
Wilkins
graysonw
true
197-391-9087
39113050916
Nathaniel
Page
npage
true
922-083-8066
87061196536
Annabelle
Parks
aparks
false
860-706-550
10221048164
Carlos
Robbins
crobbins
true
633-199-3647
85022650976
Sebastian
Mckenzie
sebastianm
true
031-821-2542
08221481578
Aiden
Mercado
aidenm
true
413-006-9553
01302174138
Jacob
Terry
jacobt
true
674-749-7019
09312515478
Hannah
Hart
hhart
false
489-395-5946
62042618284
Jaxon
Wagner
jaxonw
true
500-770-244
71081634910
Chloe
Sanders
csanders
false
714-971-5327
12302121384
Christopher
Brennan
christopherb
true
272-938-005
06253116718
Lydia
Montoya
lmontoya
false
106-629-312
13221541804
Adrian
Carver
acarver
true
355-762-7781
97111290392
Samuel
Mccullough
samuelm
true
382-502-589
66123176094
Landon
Grimes
lgrimes
true
082-649-575
10272237014
Isabella
Merrill
isabellam
false
795-762-4257
12292864824
Landon
Dale
ldale
true
959-023-135
41081330132
Madeline
Spence
mspence
false
116-600-1377
54070686488
Damian
Henderson
damianh
true
091-797-810
37091971136
Dominic
Hurley
dominich
true
842-593-567
12281078514
Mackenzie
Cooper
mcooper
false
335-422-488
12292859744
Carson
Barnes
cbarnes
true
649-653-776
13231549814
Elizabeth
Sutton
esutton
false
205-975-232
86070205666
PLAIN 121115 bytes (70%) GZIP 29553 bytes (96%)
{
"people": [
{
"firstName": "Jason",
"lastName": "Page",
"username": "jasonp",
"isMale": true,
"phone": "142-808-3743",
"nid": "12252671714"
},
{
"firstName": "Nathaniel",
"lastName": "Chaney",
"username": "nchaney",
"isMale": true,
"phone": "481-659-731",
"nid": "55122958778"
},
{
"firstName": "Alexis",
"lastName": "Christensen",
"username": "alexisc",
"isMale": false,
"phone": "802-046-8689",
"nid": "13240667404"
},
{
"firstName": "Sophie",
"lastName": "Duke",
"username": "sophied",
"isMale": false,
"phone": "316-701-3331",
"nid": "96071009282"
},
{
"firstName": "Aria",
"lastName": "Wolf",
"username": "ariaw",
"isMale": false,
"phone": "682-172-2915",
"nid": "12231830224"
},
{
"firstName": "Sebastian",
"lastName": "Hogan",
"username": "sebastianh",
"isMale": true,
"phone": "096-033-8930",
"nid": "65082565494"
},
{
"firstName": "Austin",
"lastName": "Rice",
"username": "austinr",
"isMale": true,
"phone": "558-871-007",
"nid": "91102544132"
},
{
"firstName": "Elijah",
"lastName": "Savage",
"username": "esavage",
"isMale": true,
"phone": "009-900-8985",
"nid": "10301742394"
},
{
"firstName": "Colton",
"lastName": "Morris",
"username": "cmorris",
"isMale": true,
"phone": "029-957-8223",
"nid": "84062095076"
},
{
"firstName": "Juan",
"lastName": "Bass",
"username": "jbass",
"isMale": true,
"phone": "701-810-3457",
"nid": "10311068954"
},
{
"firstName": "Brody",
"lastName": "Reese",
"username": "breese",
"isMale": true,
"phone": "320-610-636",
"nid": "82112959596"
},
{
"firstName": "Stella",
"lastName": "Bernard",
"username": "sbernard",
"isMale": false,
"phone": "134-462-1924",
"nid": "03272935528"
},
{
"firstName": "Isaac",
"lastName": "Webb",
"username": "iwebb",
"isMale": true,
"phone": "136-000-422",
"nid": "10231649814"
},
{
"firstName": "Jackson",
"lastName": "Bryan",
"username": "jacksonb",
"isMale": true,
"phone": "629-900-7729",
"nid": "83071189716"
},
{
"firstName": "Liam",
"lastName": "Beard",
"username": "lbeard",
"isMale": true,
"phone": "327-639-010",
"nid": "86050552116"
},
{
"firstName": "Parker",
"lastName": "Duffy",
"username": "pduffy",
"isMale": true,
"phone": "484-829-6473",
"nid": "56122687578"
},
{
"firstName": "Lucy",
"lastName": "Moody",
"username": "lucym",
"isMale": false,
"phone": "723-670-5321",
"nid": "77051444320"
},
{
"firstName": "Aaliyah",
"lastName": "Leonard",
"username": "aleonard",
"isMale": false,
"phone": "005-293-048",
"nid": "08281195048"
},
{
"firstName": "Brody",
"lastName": "Norris",
"username": "brodyn",
"isMale": true,
"phone": "789-653-2217",
"nid": "58050880078"
},
{
"firstName": "Juan",
"lastName": "Valenzuela",
"username": "juanv",
"isMale": true,
"phone": "060-065-140",
"nid": "93052612612"
},
{
"firstName": "Jocelyn",
"lastName": "Collins",
"username": "jcollins",
"isMale": false,
"phone": "010-257-964",
"nid": "65083166064"
},
{
"firstName": "Bentley",
"lastName": "Welch",
"username": "bentleyw",
"isMale": true,
"phone": "068-620-269",
"nid": "09293076518"
}
]
}
// PersonDataDownloader.m
#import "PersonDataDownloader_M.h"
#import "Person.h"
#import "TaskCallsSynchronizer.h"
@interface PersonDataDownloader_M ()
@property(nonatomic, strong) TaskCallsSynchronizer *synchronizer;
@end
@implementation PersonDataDownloader_M
- (void)downloadDataForPerson:(Person *)person {
self.synchronizer = [TaskCallsSynchronizer new];
self.synchronizer.completionHandler = ^(NSArray *taskDataObjects, NSArray *taskResponses) {
// Merge downloaded data here and perform the rest...
};
self.synchronizer.errorHandler = ^(NSArray *errors) {
NSLog(@"All calls went bad...");
};
NSURLSessionDataTask *personalInfoTask = [self personalInfoTaskForPerson:person synchronizer:self.synchronizer];
NSURLSessionDataTask *accountNumberTask = [self accountNumberTaskForPerson:person synchronizer:self.synchronizer];
[self.synchronizer addTask:personalInfoTask withName:@"InfoTask"];
[self.synchronizer addTask:accountNumberTask withName:@"AccountTask"];
[personalInfoTask resume];
[accountNumberTask resume];
}
#pragma mark - Tasks
- (NSURLSessionDataTask *)personalInfoTaskForPerson:(Person *)person synchronizer:(TaskCallsSynchronizer *)synchronizer {
NSURLSession *session = [NSURLSession sharedSession];
__typeof(synchronizer) __weak weakSynchronizer = synchronizer;
NSURLSessionDataTask *personalInfoTask = [session dataTaskWithURL:[self urlForPersonsPersonalInfo:person]
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSString *taskName = @"InfoTask";
if (data && !error) {
[weakSynchronizer completeTaskWithName:taskName data:data response:response];
} else {
[weakSynchronizer errorDidOccur:error forTaskWithName:taskName];
}
}];
return personalInfoTask;
}
- (NSURLSessionDataTask *)accountNumberTaskForPerson:(Person *)person synchronizer:(TaskCallsSynchronizer *)synchronizer {
NSURLSession *session = [NSURLSession sharedSession];
__typeof(synchronizer) __weak weakSynchronizer = synchronizer;
NSURLSessionDataTask *accountNumberTask = [session dataTaskWithURL:[self urlForPersonsAccountNumber:person]
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSString *taskName = @"AccountTask";
if (data && !error) {
[weakSynchronizer completeTaskWithName:taskName data:data response:response];
} else {
[weakSynchronizer errorDidOccur:error forTaskWithName:taskName];
}
}];
return accountNumberTask;
}
#pragma mark - URLs
- (NSURL *)urlForPersonsPersonalInfo:(Person *)person {
NSString *urlString = [NSString stringWithFormat:@"http://e1.com/persons/%ld", (long)person.id];
return [[NSURL alloc] initWithString:urlString];
}
- (NSURL *)urlForPersonsAccountNumber:(Person *)person {
NSString *urlString = [NSString stringWithFormat:@"http://e2.com/accounts/%ld", (long)person.id];
return [[NSURL alloc] initWithString:urlString];
}
@end
// TaskCallSynchronizer.m
#import "TaskCallsSynchronizer.h"
@interface TaskCallsSynchronizer ()
@property(nonatomic, readonly) NSMapTable *tasksMap;
@property(nonatomic, readonly) NSMutableArray *dataObjects;
@property(nonatomic, readonly) NSMutableArray *responses;
@property(nonatomic, readonly) NSMutableArray *errors;
@property(nonatomic) BOOL errorEncountered;
@end
@implementation TaskCallsSynchronizer
- (id)init {
self = [super init];
if (self) {
_tasksMap = [NSMapTable strongToWeakObjectsMapTable];
_dataObjects = [NSMutableArray array];
_responses = [NSMutableArray array];
_errors = [NSMutableArray array];
}
return self;
}
- (void)addTask:(NSURLSessionDataTask *)task withName:(NSString *)name {
[self.tasksMap setObject:task forKey:name];
}
- (void)completeTaskWithName:(NSString *)name data:(NSData *)data response:(NSURLResponse *)response {
@synchronized (self) {
NSURLSessionDataTask *task = [self.tasksMap objectForKey:name];
BOOL isDownloadStateValid = task.state != NSURLSessionTaskStateCompleted && !self.errorEncountered;
if (isDownloadStateValid) {
NSLog(@"Ups, something's wrong.");
} else {
[self.dataObjects addObject:data];
[self.responses addObject:response];
[self.tasksMap removeObjectForKey:name];
if ([self.tasksMap count] == 0 && self.completionHandler) {
self.completionHandler(self.dataObjects, self.responses);
}
}
}
}
- (void)errorDidOccur:(NSError *)error forTaskWithName:(NSString *)name {
@synchronized (self) {
self.errorEncountered = YES;
[self.errors addObject:error];
[self.tasksMap removeObjectForKey:name];
if ([self.tasksMap count] == 0 && self.errorHandler) {
self.errorHandler(self.errors);
}
}
}
@end
protected void onResume() {
super.onResume();
try {
download();
} catch (Exception e) {
Log.e(TAG, "Error while downloading data", e);
}
}
public void download() throws ExecutionException, InterruptedException {
Future<Response<JsonObject>> personFuture = Ion.
with(this).
load("http://e1.com/persons/123").
asJsonObject().withResponse();
Future<Response<JsonObject>> accountFuture = Ion.
with(this).
load("http://e2.com/accounts/456").
asJsonObject().
withResponse();
Response<JsonObject> personResponse = personFuture.get();
Response<JsonObject> accountResponse = accountFuture.get();
if (personResponse.getException() != null && accountResponse.getException() != null) {
JsonObject person = personResponse.getResult().getAsJsonObject();
JsonObject account = personResponse.getResult().getAsJsonObject();
String firstName = person.getAsJsonPrimitive("firstName").toString();
String lastName = person.getAsJsonPrimitive("lastName").toString();
String accountNo = account.getAsJsonPrimitive("accountNo").toString();
} else {
Log.e(TAG, "Error while downloading account", accountResponse.getException());
Log.e(TAG, "Error while downloading person", personResponse.getException());
}
}
def parts = [
"http://e1.com/persons/123": ['firstName', 'lastName'],
"http://e2.com/accounts/456": ['accountNo'],
]
def output = withPool(2) {
return parts.collectParallel({ url, fields ->
def json = new JsonSlurper().parse(url as URL)
return fields.collect ({ field ->
["$field": json[field]]
})
}).flatten().sum()
}
POST /following
{
"from": 123,
"to": 456
}
POST /users/456/follow
Expires: Sat, 26 Jul 1997 05:00:00 GMT
GET /users?page=:page_number
Page size 3
Page 1: Arthur Bob Celine
Delete: Bob
Page 1: Arthur Bobby Daniel
Page 2: Eve Fred George
{
// ...
"nextPage": "/users?since=5476238046501"
}