Graphon API

S3 API

Use S3 tools and SDKs with an API key: the endpoint, signing, client setup, every S3 operation that storage supports, and the common errors.

Graphon Storage speaks the Amazon S3 API. Point an S3 tool or SDK at your workspace S3 endpoint, and sign with an API key from that workspace. Each operation below has its own page with its parameters, responses, errors, and samples.

Connection

SettingValue
S3 endpointhttps://wspq7ws2np5l8z4.storage.beta.graphon.sh
JSON APIhttps://storage.beta.graphon.sh
Regionus-east-1
AddressingPath style: /{bucket}/{key}
SignatureAWS Signature Version 4, in a header or a presigned URL
Access key IDThe part of the API key between the _ and the .
Secret access keyThe whole API key

Replace wspq7ws2np5l8z4 in every example with your workspace ID. The key must belong to the workspace in the hostname. The bare storage host serves the JSON API only. Use the workspace host for S3, including public object links and presigned requests.

us-east-1 is only the signing region. Your data stays in the location that you chose for the bucket. A key covers every bucket in its workspace, and each operation needs the role on its page. See Authentication & keys for how to get the credentials and presign a URL.

Bucket names and rename

Names are unique within one workspace and are case-sensitive. Use 1–255 ASCII letters, digits, periods, underscores, or hyphens. The exact names . and .. are invalid. Another workspace can use the same name.

Rename through the JSON API or graphon buckets rename. S3 has no RenameBucket operation. The bucket ID and data stay unchanged. Update name-based URLs and client settings after a rename. See Renaming buckets.

Set up a client

The aws CLI reads the graphon profile. The SDK samples read the key from GRAPHON_API_KEY. Each operation page uses the same setup.

~/.aws/config

# Replace wspq7ws2np5l8z4 with your workspace ID.
# ~/.aws/config
[profile graphon]
credential_process = graphon s3-credentials --format process
endpoint_url = https://wspq7ws2np5l8z4.storage.beta.graphon.sh
region = us-east-1
s3 =
  addressing_style = path

aws CLI

aws s3 ls --profile graphon
aws s3 cp ./checkout-timeout.json s3://support-tickets/incidents/ --profile graphon

boto3

# Replace wspq7ws2np5l8z4 with your workspace ID.
import os

import boto3
from botocore.config import Config

api_key = os.environ["GRAPHON_API_KEY"]
access_key_id = api_key.split("_", 1)[1].split(".")[0]

s3 = boto3.client(
    "s3",
    endpoint_url="https://wspq7ws2np5l8z4.storage.beta.graphon.sh",
    region_name="us-east-1",
    aws_access_key_id=access_key_id,
    aws_secret_access_key=api_key,
    config=Config(signature_version="s3v4", s3={"addressing_style": "path"}),
)
print(s3.list_objects_v2(Bucket="support-tickets", Prefix="incidents/"))

AWS SDK for JavaScript

import { ListObjectsV2Command } from '@aws-sdk/client-s3';

// Replace wspq7ws2np5l8z4 with your workspace ID.
import { S3Client } from '@aws-sdk/client-s3';

const apiKey = process.env.GRAPHON_API_KEY;
if (!apiKey) throw new Error('Set GRAPHON_API_KEY.');
const accessKeyId = apiKey.split('_')[1].split('.')[0];

const s3 = new S3Client({
  endpoint: 'https://wspq7ws2np5l8z4.storage.beta.graphon.sh',
  region: 'us-east-1',
  forcePathStyle: true,
  credentials: { accessKeyId, secretAccessKey: apiKey },
});

console.log(await s3.send(new ListObjectsV2Command({
  Bucket: 'support-tickets',
  Prefix: 'incidents/',
})));

rclone

# Replace wspq7ws2np5l8z4 with your workspace ID.
# ~/.config/rclone/rclone.conf
[graphon]
type = s3
provider = Other
endpoint = https://wspq7ws2np5l8z4.storage.beta.graphon.sh
region = us-east-1
force_path_style = true
env_auth = true

# Then, with GRAPHON_API_KEY set, this sets AWS_ACCESS_KEY_ID and
# AWS_SECRET_ACCESS_KEY for rclone:
# eval "$(graphon s3-credentials)"
# rclone ls graphon:support-tickets

Operations

Storage supports these operations. A partial operation supports the common case. Its page lists what differs from Amazon S3.

Buckets

Objects

Multipart uploads

Versioning & retention

Object tags

Common errors

An error has an XML body with a Code and a Message. Every response has an x-amz-request-id header. Send it to support when you report a problem. Any request can get these errors. Each operation page lists its own errors.

StatusCodeMeaningWhat to do
403AccessDeniedThe request has no signature, the presigned URL expired, or the role of the key is too low.Sign the request, presign a new URL, or use a key with a higher role.
403AccessDeniedThe key belongs to a workspace other than the one in the hostname, or that workspace is unknown or suspended.Use the S3 endpoint of the workspace that owns the key.
400InvalidBucketNameThe bucket name in the path breaks the naming rules.Use 1 to 255 ASCII letters, digits, periods, underscores, or hyphens. A name cannot be . or ...
403InvalidAccessKeyIdNo key has this access key ID, or the key was revoked.Check the access key ID. It is the part of the API key between _ and ..
403ExpiredTokenThe key has expired.Create a new key.
403SignatureDoesNotMatchThe signature does not match the request.Use the whole API key as the secret access key, sign for us-east-1, and use path-style addressing.
403RequestTimeTooSkewedThe request time is too far from the time of the server.Set the clock of the client with NTP.
403AuthorizationQueryParametersErrorA presigned URL has an X-Amz-Date or X-Amz-Expires value that is not valid.Presign the URL again.
400InvalidRequestA signed request has no x-amz-content-sha256 header.Send the header. SDKs and the aws CLI send it by themselves.
400InvalidURIThe path or the query has a % escape that does not decode.Percent-encode the key and the query values correctly.
405MethodNotAllowedThe path does not accept this HTTP method.Check the method and the path of the operation.
413EntityTooLargeThe body is larger than 200 MiB.Use a multipart upload.
501NotImplementedThe request uses an S3 feature that storage does not support.See Not supported below.
503SlowDownThe bucket has too many writes in progress.Retry after the Retry-After time. SDKs retry by themselves.
500InternalErrorStorage could not handle the request.Retry with backoff. Send the x-amz-request-id to support if it continues.

Browser requests

Storage answers a CORS preflight (OPTIONS) on any S3 path with 204. It allows every origin and header, and the GET, PUT, POST, DELETE, and HEAD methods. A preflight reads and changes nothing. A browser can use a presigned URL, or read an object from a public-read bucket with no signature.

Not supported

These requests return 501 NotImplemented. An S3 request to the bare storage host returns 404 with a JSON error. Storage ignores the other S3 features that it does not support. Each operation page names the parameters that it ignores.

RequestResult
GET /{bucket}?websiteWebsite, CORS, and lifecycle configuration return 501.
GET /{bucket}/{key}?aclObject ACLs return 501. Use the bucket permission in the JSON API.
GET /{bucket}/{key}?legal-holdLegal hold returns 501.
POST /{bucket}/{key}?selectS3 Select returns 501.
PUT /{bucket}/{key} with x-amz-server-side-encryption-customer-algorithmSSE-C returns 501. Providers encrypt every object at rest.

Larger files

One PUT or one multipart part carries a limited size. The aws CLI and the SDKs switch to a multipart upload for a large file by themselves. See Limits.
Was this page helpful?
View as Markdown