Scale up as you grow — whether you're running one virtual machine or ten thousand.

From GPU-powered inference and Kubernetes to managed databases and storage, get everything you need to build, scale, and deploy intelligent applications.

Hello,
I am trying to use Digitalocean spaces using the AWS-SDK V2 for Golang.
Everything works almost fine until the point where I attempt to perform an operation, then I get the error below;
operation error S3: ListObjectsV2, https response error StatusCode: 501, RequestID: , HostID: , api error NotImplemented: Server does not support one or more requested headers. Please see https://developers.digitalocean.com/documentation/spaces/#aws-s3-compatibility
Going through the error link, I understand that certain operations on Spaces on DO are not supported using AWS-SDK, however, CRUD operations are supported.
Also, this is very similar to the Upload file example in the Spaces API documentation here
Here’s a snippet of the code being used to perform the operation;
Go
package graph
// This file will be automatically regenerated based on the schema, any resolver implementations
// will be copied through when generating and any unknown code will be moved to the end.
import (
"context"
"fmt"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/credentials"
"os"
"time"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/satori/go.uuid"
"github.com/vickywane/api/graph/generated"
"github.com/vickywane/api/graph/model"
)
type S3PutObjectAPI interface {
PutObject(ctx context.Context,
params *s3.PutObjectInput,
optFns ...func(*s3.Options)) (*s3.PutObjectOutput, error)
}
func PutFile(c context.Context, api S3PutObjectAPI, input *s3.PutObjectInput) (*s3.PutObjectOutput, error) {
return api.PutObject(c, input)
}
func (r *mutationResolver) UploadProfileImage(ctx context.Context, input model.ProfileImage) (bool, error) {
SpaceName := os.Getenv("DO_SPACE_NAME")
key := os.Getenv("ACCESS_KEY")
secret := os.Getenv("ACCESS_SECRET")
token := os.Getenv("API_TOKEN")
_, userErr := r.GetUserField("id", *input.UserID); if userErr != nil {
fmt.Errorf("error getting user: %v", userErr)
}
customResolver := aws.EndpointResolverFunc(func(service, region string) (aws.Endpoint, error) {
return aws.Endpoint{
URL: fmt.Sprintf("https://fra1.digitaloceanspaces.com"),
}, nil
})
cfg, err := config.LoadDefaultConfig(
context.TODO(),
func(options *config.LoadOptions) error {
options.Credentials = credentials.NewStaticCredentialsProvider(key, secret, token)
options.EndpointResolver = customResolver
options.Region = "fra1"
return nil
},
); if err != nil {
fmt.Errorf("error getting config: %v", err)
}
client := s3.NewFromConfig(cfg)
objectsInput := &s3.ListObjectsV2Input{
Bucket: aws.String(SpaceName),
}
objects, err := client.ListObjectsV2(context.TODO(), objectsInput)
// print out <nil> even when there are files in the bucket
fmt.Println(objects)
fileInput := &s3.PutObjectInput{
Bucket: aws.String(SpaceName),
Key: aws.String(input.File.Filename),
Body: input.File.File,
ACL: "public-read",
}
_, putErr := client.PutObject(context.TODO(), fileInput); if putErr != nil {
fmt.Printf("error uploading file: %v", err)
}
return true, nil
}
Note: This operation is being performed from a resolver function within a GraphQL backend application. Here is a link to the entire resolver file.
Roger Henman
Roger Henman
Paul Adeyenuwo
wtrenker
Popescu Crina-Mariana
Setor Blagogee
daniel.carpenter01
Morzaram
Sai Aung Kaung Myat
alenn
Jake W