File Upload di GraphQL
GraphQL tidak natively support file upload. Ada beberapa pendekatan, masing-masing dengan trade-off.
Approach 1: Presigned URL (Recommended)
# Schema
type Mutation {
getUploadUrl(filename: String!, contentType: String!): UploadUrl!
}
type UploadUrl {
url: String!
key: String!
}
# Flow:
# 1. Client minta presigned URL via GraphQL
# 2. Client upload langsung ke S3/R2 via presigned URL
# 3. Client kirim file key kembali via mutation
mutation {
getUploadUrl(filename: "avatar.jpg", contentType: "image/jpeg") {
url # S3 presigned URL
key # "uploads/abc123.jpg"
}
}
# Setelah upload ke S3:
mutation {
updateProfile(avatarKey: "uploads/abc123.jpg") {
id
avatarUrl
}
}
Approach 2: graphql-upload (Multipart)
// Server
import graphqlUploadExpress from "graphql-upload/graphqlUploadExpress.mjs";
app.use(graphqlUploadExpress({ maxFileSize: 10_000_000 })); // 10MB
// Schema: scalar Upload built-in
// Resolver
uploadAvatar: async (_, { file }, { user }) => {
const { createReadStream, filename } = await file;
const stream = createReadStream();
// pipe ke storage...
}
// Client (Apollo)
const UPLOAD = gql\`
mutation Upload($file: Upload!) {
uploadAvatar(file: $file) { url }
}
\`;
const [upload] = useMutation(UPLOAD);
upload({ variables: { file: inputRef.current.files[0] } });
Recommendation
- Presigned URL — Scalable, file tidak lewat server, works dengan CDN
- graphql-upload — Simple untuk file kecil, tapi file lewat server (bottleneck)
- Separate REST endpoint — /upload via REST, referensi via GraphQL