Go (aws-sdk-go-v2)
Fil One works with aws-sdk-go-v2 — it is S3-API compatible. Configure the client to point at the Fil One endpoint with UsePathStyle: true and use the standard S3 API. A few S3 operations are not supported; see S3 Compatibility for the exceptions.
Examples here use eu-west-1, the default region. For a bucket in us-east-1, use https://us-east-1.s3.filonecontent.com and Region: "us-east-1". The endpoint, the region, and your access key must all refer to the same region.
Installation
go get github.com/aws/aws-sdk-go-v2/aws
go get github.com/aws/aws-sdk-go-v2/credentials
go get github.com/aws/aws-sdk-go-v2/service/s3
go get github.com/aws/aws-sdk-go-v2/service/s3/types
Client configuration
package main
import (
"os"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/credentials"
"github.com/aws/aws-sdk-go-v2/service/s3"
)
func newClient() *s3.Client {
return s3.New(s3.Options{
BaseEndpoint: aws.String("https://eu-west-1.s3.filonecontent.com"),
Region: "eu-west-1",
Credentials: credentials.NewStaticCredentialsProvider(
os.Getenv("FIL_ACCESS_KEY"),
os.Getenv("FIL_SECRET_KEY"),
"",
),
UsePathStyle: true,
})
}
Set FIL_ACCESS_KEY and FIL_SECRET_KEY as environment variables. Never hardcode credentials in source code.
The operation snippets below are fragments: each assumes the client returned by newClient() above and a ctx (e.g. ctx := context.TODO()) in scope, and shows only the imports specific to that snippet.
Core operations
Create a bucket
CreateBucket is region-dependent. It is not available in eu-west-1 — use the Fil One dashboard there, via Buckets → Create bucket. In us-east-1, with a key that has the CreateBucket permission:
_, err := client.CreateBucket(ctx, &s3.CreateBucketInput{
Bucket: aws.String("my-bucket"),
})
Note that versioning and Object Lock can only be set when the bucket is created, and only from the dashboard. See Buckets.
Upload an object
import (
"bytes"
"os"
)
// Upload bytes
_, err := client.PutObject(ctx, &s3.PutObjectInput{
Bucket: aws.String("my-bucket"),
Key: aws.String("data/file.json"),
Body: bytes.NewReader([]byte(`{"key":"value"}`)),
ContentType: aws.String("application/json"),
})
// Upload a file
f, _ := os.Open("report.pdf")
defer f.Close()
_, err = client.PutObject(ctx, &s3.PutObjectInput{
Bucket: aws.String("my-bucket"),
Key: aws.String("reports/report.pdf"),
Body: f,
ContentType: aws.String("application/pdf"),
})
Download an object
import (
"io"
"os"
)
result, err := client.GetObject(ctx, &s3.GetObjectInput{
Bucket: aws.String("my-bucket"),
Key: aws.String("reports/report.pdf"),
})
if err != nil {
// handle error
}
defer result.Body.Close()
out, _ := os.Create("local-report.pdf")
defer out.Close()
io.Copy(out, result.Body)
List objects
import "fmt"
paginator := s3.NewListObjectsV2Paginator(client, &s3.ListObjectsV2Input{
Bucket: aws.String("my-bucket"),
})
for paginator.HasMorePages() {
page, err := paginator.NextPage(ctx)
if err != nil {
// handle error
}
for _, obj := range page.Contents {
// obj.Size is a *int64; dereference it with aws.ToInt64 to print the number
fmt.Println(*obj.Key, aws.ToInt64(obj.Size))
}
}
Delete an object
_, err := client.DeleteObject(ctx, &s3.DeleteObjectInput{
Bucket: aws.String("my-bucket"),
Key: aws.String("reports/report.pdf"),
})
Presigned URLs
import (
"time"
"github.com/aws/aws-sdk-go-v2/service/s3"
)
presigner := s3.NewPresignClient(client)
// Download URL valid for 1 hour
downloadReq, err := presigner.PresignGetObject(ctx, &s3.GetObjectInput{
Bucket: aws.String("my-bucket"),
Key: aws.String("reports/report.pdf"),
}, s3.WithPresignExpires(time.Hour))
// Upload URL valid for 15 minutes
uploadReq, err := presigner.PresignPutObject(ctx, &s3.PutObjectInput{
Bucket: aws.String("my-bucket"),
Key: aws.String("uploads/new-file.txt"),
}, s3.WithPresignExpires(15*time.Minute))
Error handling
import (
"errors"
"github.com/aws/smithy-go"
)
_, err := client.GetObject(ctx, &s3.GetObjectInput{
Bucket: aws.String("my-bucket"),
Key: aws.String("missing.txt"),
})
if err != nil {
var apiErr smithy.APIError
if errors.As(err, &apiErr) {
fmt.Println(apiErr.ErrorCode(), apiErr.ErrorMessage())
}
}
See the Error Reference for a full list of error codes.