Amazon Simple Storage Service (S3) support
ASIHTTPRequest comes with several classes that make it easy to talk to Amazon S3 using the S3 REST API.
The classes
S3 support is built around 6 classes:
ASIS3Request
An ASIHTTPRequest subclass that handles the basics of talking to S3. It generates the HTTP headers S3 requires for you.
Generally, you won't use ASIS3Request directly, but one of the subclasses instead.
ASIS3ObjectRequest
This ASIS3Request subclass allows you to work with objects stored in a bucket on Amazon S3. You can use it to upload, download, delete and copy objects.
ASIS3BucketRequest
This ASIS3Request subclass allows you to work with buckets stored on Amazon S3. You can use it to create, modify and delete buckets, and perform a query to list the contents of a bucket based on parameters you supply.
ASIS3ServiceRequest
This class allows you to obtain a list of the buckets you have in your S3 account.
ASIS3BucketObject
Instances of this class represent an object stored in a bucket. ASIS3BucketRequests return an array of these when you perform a query to list the contents of a bucket.
ASIS3Bucket
An instance of this class represents a bucket. ASIS3ServiceRequests can return an array of these.
Sample code
Most of these examples use synchronous requests for brevity, you should normally use a queue or [request startAsynchronous] to perform these operations asynchronously (more info..).
GET an object
In this example, we'll get the object from S3 that is stored at http://my-bucket.s3.amazonaws.com/path/to/the/object.
NSString *secretAccessKey = @"my-secret-access-key";
NSString *accessKey = @"my-access-key";
NSString *bucket = @"my-bucket";
NSString *path = @"path/to/the/object";
ASIS3ObjectRequest *request = [ASIS3ObjectRequest requestWithBucket:bucket key:path];
[request setSecretAccessKey:secretAccessKey];
[request setAccessKey:accessKey];
[request startSynchronous];
if (![request error]) {
NSData *data = [request responseData];
} else {
NSLog(@"%@",[[request error] localizedDescription]);
}
If you are downloading a large object, you can save memory by downloading directly to a file on disk.
PUT an object
It can be a pain to have to set your access key and secret access key to every request, so we'll set the sharedAccessKey and sharedSecretAccessKey. The next time we perform a request without setting these, it will use these values.
[ASIS3Request setSharedSecretAccessKey:@"my-secret-access-key"];
[ASIS3Request setSharedAccessKey:@"my-access-key"];
NSString *filePath = @"/somewhere/on/disk.txt";
ASIS3ObjectRequest *request =
[ASIS3ObjectRequest PUTRequestForFile:filePath withBucket:@"my-bucket" key:@"path/to/the/object"];
[request startSynchronous];
if ([request error]) {
NSLog(@"%@",[[request error] localizedDescription]);
}
DELETE an object
We won't set the access keys this time, because we've already set the shared ones.
ASIS3ObjectRequest *request = [ASIS3ObjectRequest DELETERequestWithBucket:@"my-bucket"
key:@"path/to/the/object"];
[request startSynchronous];
if ([request error]) {
NSLog(@"%@",[[request error] localizedDescription]);
}
COPY an object
ASIS3ObjectRequest *request =
[ASIS3ObjectRequest COPYRequestFromBucket:@"my-bucket" key:@"/path/to/the/object"
toBucket:@"my-bucket" key:@"/new/path/to/the/object"];
[request startSynchronous];
if ([request error]) {
NSLog(@"%@",[[request error] localizedDescription]);
}
Fetch a list of objects in a bucket
Use an ASIS3BucketRequest to return a list of the objects in a bucket that match your query parameters.
This example will fetch information about no more than 50 objects in http://my-bucket.s3.amazonaws.com/images/jpegs.
[listRequest objects] is an array of ASIS3BucketObjects.
ASIS3BucketRequest *listRequest = [ASIS3BucketRequest requestWithBucket:@"my-bucket"];
[listRequest setPrefix:@"images/jpegs"];
[listRequest setMaxResultCount:50]; // Max number of results we want
[listRequest startSynchronous];
if (![listRequest error]) {
NSLog(@"%@",[listRequest objects]);
}
Downloading objects from the list
This time, we'll do something with the result of the list query.
- (void)download25ImagesToDisk
{
// We'll use a queue to perform the operations in the background
[[self queue] cancelAllOperations];
[self setQueue:[ASINetworkQueue queue]];
// First grab a list of 25 images
ASIS3BucketRequest *listRequest = [ASIS3BucketRequest requestWithBucket:@"my-bucket"];
[listRequest setPrefix:@"images/jpegs"];
[listRequest setMaxResultCount:25];
[listRequest setDelegate:self];
[listRequest setDidFinishSelector:@selector(finishedDownloadingImageList:)];
[listRequest setDidFailSelector:@selector(failedDownloadingImageList:)];
[[self queue] addOperation:listRequest];
}
- (void)failedDownloadingImageList:(ASIHTTPRequest *)listRequest
{
NSLog(@"Failed downloading a list of images because '%@'",
[[listRequest error] localizedDescription]);
}
- (void)finishedDownloadingImageList:(ASIHTTPRequest *)listRequest
{
// Once we get here, we'll have a list of 25 images to download
[[self queue] reset];
[[self queue] setRequestDidFinishSelector:@selector(requestDone:)];
[[self queue] setRequestDidFailSelector:@selector(requestFailed:)];
[[self queue] setDelegate:self];
// Loop through all the objects returned by the query
// and create a request to download them to disk
int i=0;
for (ASIS3BucketObject *object in [listRequest objects]) {
ASIS3ObjectRequest *request = [object GETRequest];
NSString *downloadPath = [NSString stringWithFormat:@"/Users/ben/Desktop/images/%hi.jpg",i];
[request setDownloadDestinationPath:downloadPath];
[[self queue] addOperation:request];
i++;
}
// Start the queue
[[self queue] go];
}
- (void)requestDone:(ASIS3Request *)request
{
NSLog(@"Finished downloading an image");
}
- (void)requestFailed:(ASIS3Request *)request
{
NSLog(@"Dammit, something went wrong: %@",[[request error] localizedDescription]);
}
You can also create requests to PUT new files to replace objects in the list using [object PUTRequestWithFile:path], or to DELETE objects in the list using [object DELETERequest].
Get a list of buckets
ASIS3ServiceRequest *request = [ASIS3ServiceRequest serviceRequest];
[request startSynchronous];
if (![request error]) {
NSArray *buckets = [request buckets]; // An array of ASIS3Bucket objects
}
Create a bucket
ASIS3BucketRequest *request = [ASIS3BucketRequest PUTRequestWithBucket:@"my-bucket"];
[request startSynchronous];
if ([request error]) {
NSLog(@"%@",[[request error] localizedDescription]);
}
Delete a bucket
ASIS3BucketRequest *request = [ASIS3BucketRequest DELETERequestWithBucket:@"my-bucket"];
[request startSynchronous];
if ([request error]) {
NSLog(@"%@",[[request error] localizedDescription]);
}
GZIP data
New in ASIHTTPRequest 1.0.3 is the ability to gzip request bodies (More here). This may be especially useful for applications that store data on S3, because:
- Data is stored compressed, so it uses less space and costs you less money
- Data is uploaded and downloaded compressed, so it saves money and makes requests faster in both directions
ASIS3ObjectRequest *request =
[ASIS3ObjectRequest PUTRequestForFile:filePath withBucket:@"my-bucket" key:@"path/to/the/object"];
[request setShouldCompressRequestBody:YES];
Connecting to S3 via HTTPS
ASIS3ObjectRequest *request =
[ASIS3ObjectRequest PUTRequestForFile:filePath withBucket:@"my-bucket" key:@"path/to/the/object"];
[request requestScheme:ASIS3RequestSchemeHTTPS];
Connecting to a different service with an S3-like API
ASIHTTPRequest only supports the official Amazon S3 API. As of v1.8, with some small changes, you may be able to use it with other services that use a similar API. To do so, change ASIS3Request's S3Host method to return the hostname of the service you are connecting to. If the service you are connecting to requires a slightly different url format (for example, some services do not send the bucket name in a subdomain), you may also need to modify the buildURL methods in the S3 classes you are using.