S3 Storage Support

GQLForge can integrate with Amazon S3 and S3-compatible storage services (MinIO, Cloudflare R2, etc.) using the @s3 directive. This enables presigned URL generation, object listing, and deletion directly from your GraphQL API.

Connecting to S3

Register an S3 endpoint with @link using the S3 link type:

schema
@server(port: 8000)
@link(id: "aws", type: S3, src: "https://s3.ap-northeast-1.amazonaws.com", meta: { region: "ap-northeast-1" }) {
  query: Query
  mutation: Mutation
}

Connection Parameters

The @link directive for S3 accepts the following:

ParameterLocationDescription
id@linkIdentifier to reference this connection in @s3(linkId: ...).
src@linkThe S3 endpoint URL. Optional for AWS S3 (the SDK resolves the endpoint from the region). Required for S3-compatible services.
meta.region@linkAWS region (default: us-east-1).
meta.forcePathStyle@linkUse path-style addressing (default: false). Required for MinIO.

AWS Credentials

Credentials are resolved via the standard AWS credential chain:

  1. Environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)
  2. Shared credentials file (~/.aws/credentials)
  3. IAM instance profile (EC2, ECS, Lambda)
  4. Web identity token (EKS)

No credentials are stored in the GraphQL schema.

S3-Compatible Services

MinIO

schema @link(id: "minio", type: S3, src: "http://localhost:9000", meta: { region: "us-east-1", forcePathStyle: true }) {
  query: Query
}

Cloudflare R2

schema @link(id: "r2", type: S3, src: "https://<ACCOUNT_ID>.r2.cloudflarestorage.com", meta: { region: "auto" }) {
  query: Query
}

Multiple S3 Connections

You can define multiple S3 connections and select them with the linkId field:

schema
@link(id: "aws", type: S3, src: "https://s3.ap-northeast-1.amazonaws.com", meta: { region: "ap-northeast-1" })
@link(id: "minio", type: S3, src: "http://localhost:9000", meta: { region: "us-east-1", forcePathStyle: true }) {
  query: Query
  mutation: Mutation
}

type Query {
  awsFile(key: String!): String!
  @s3(bucket: "prod-bucket", operation: GET_PRESIGNED_URL, key: "{{.args.key}}", linkId: "aws")

  localFile(key: String!): String!
  @s3(bucket: "dev-bucket", operation: GET_PRESIGNED_URL, key: "{{.args.key}}", linkId: "minio")
}

The @s3 Directive

Use @s3 on fields to map them to S3 operations:

type Query {
  getFileUrl(key: String!): String!
  @s3(bucket: "my-bucket", operation: GET_PRESIGNED_URL, key: "{{.args.key}}", expiration: 3600)

  listFiles(prefix: String): JSON! @s3(bucket: "my-bucket", operation: LIST, prefix: "{{.args.prefix}}")
}

type Mutation {
  uploadUrl(key: String!, contentType: String): String!
  @s3(bucket: "my-bucket", operation: PUT_PRESIGNED_URL, key: "{{.args.key}}", contentType: "{{.args.contentType}}")

  deleteFile(key: String!): Boolean! @s3(bucket: "my-bucket", operation: DELETE, key: "{{.args.key}}")
}

See @s3 Directive for the full field reference.

Enabling S3 Support

S3 support requires the s3 feature flag:

cargo build --features s3

This pulls in aws-sdk-s3 and aws-config as dependencies.