Auto-indexing service and GraphQL API for AT Protocol Records
quickslice.slices.network/
atproto
gleam
graphql
1# Working with Blobs
2
3Blobs store binary data like images, videos, and files. Upload separately and reference by CID (Content Identifier).
4
5## Upload Blob
6
7Upload binary data encoded as base64:
8
9```graphql
10mutation {
11 uploadBlob(
12 data: "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAY..."
13 mimeType: "image/png"
14 ) {
15 ref
16 mimeType
17 size
18 }
19}
20```
21
22Response:
23
24```json
25{
26 "data": {
27 "uploadBlob": {
28 "ref": "bafkreiabc123xyz...",
29 "mimeType": "image/png",
30 "size": 1024
31 }
32 }
33}
34```
35
36## Blob Reference
37
38A blob reference contains:
39
40- `ref`: CID of the blob content
41- `mimeType`: MIME type (e.g., `image/jpeg`, `image/png`)
42- `size`: Size in bytes
43
44## Using Blobs in Records
45
46### Profile Avatar
47
48```graphql
49mutation {
50 updateAppBskyActorProfile(
51 rkey: "self"
52 input: {
53 displayName: "Alice"
54 avatar: {
55 ref: "bafkreiabc123..."
56 mimeType: "image/jpeg"
57 size: 125000
58 }
59 }
60 ) {
61 displayName
62 avatar {
63 ref
64 mimeType
65 size
66 url
67 }
68 }
69}
70```
71
72### Profile Banner
73
74```graphql
75mutation {
76 updateAppBskyActorProfile(
77 rkey: "self"
78 input: {
79 displayName: "Alice"
80 banner: {
81 ref: "bafkreixyz789..."
82 mimeType: "image/jpeg"
83 size: 450000
84 }
85 }
86 ) {
87 displayName
88 banner {
89 ref
90 mimeType
91 size
92 url
93 }
94 }
95}
96```
97
98## Blob URLs
99
100Blobs generate CDN URLs automatically. Use the `url` field with optional presets:
101
102### Default URL
103
104```graphql
105query {
106 appBskyActorProfile {
107 edges {
108 node {
109 avatar {
110 ref
111 url
112 }
113 }
114 }
115 }
116}
117```
118
119Returns: `https://cdn.bsky.app/img/feed_fullsize/plain/did:plc:.../bafkreiabc123@jpeg`
120
121### Avatar Preset
122
123```graphql
124query {
125 appBskyActorProfile {
126 edges {
127 node {
128 avatar {
129 ref
130 url(preset: "avatar")
131 }
132 }
133 }
134 }
135}
136```
137
138Returns: `https://cdn.bsky.app/img/avatar/plain/did:plc:.../bafkreiabc123@jpeg`
139
140### Banner Preset
141
142```graphql
143query {
144 appBskyActorProfile {
145 edges {
146 node {
147 banner {
148 url(preset: "banner")
149 }
150 }
151 }
152 }
153}
154```
155
156Returns: `https://cdn.bsky.app/img/banner/plain/did:plc:.../bafkreixyz789@jpeg`
157
158## Available Presets
159
160- `avatar` - Optimized for profile avatars (square, small)
161- `banner` - Optimized for profile banners (wide, medium)
162- `feed_thumbnail` - Thumbnails in feed view
163- `feed_fullsize` - Full size images in feed (default)
164
165## Complete Example: Update Profile with Images
166
167### Step 1: Upload Avatar
168
169```graphql
170mutation UploadAvatar($avatarData: String!) {
171 uploadBlob(data: $avatarData, mimeType: "image/jpeg") {
172 ref
173 mimeType
174 size
175 }
176}
177```
178
179Variables:
180```json
181{
182 "avatarData": "base64EncodedJpegData..."
183}
184```
185
186Response:
187```json
188{
189 "data": {
190 "uploadBlob": {
191 "ref": "bafkreiabc123avatar",
192 "mimeType": "image/jpeg",
193 "size": 125000
194 }
195 }
196}
197```
198
199### Step 2: Upload Banner
200
201```graphql
202mutation UploadBanner($bannerData: String!) {
203 uploadBlob(data: $bannerData, mimeType: "image/jpeg") {
204 ref
205 mimeType
206 size
207 }
208}
209```
210
211Variables:
212```json
213{
214 "bannerData": "base64EncodedJpegData..."
215}
216```
217
218Response:
219```json
220{
221 "data": {
222 "uploadBlob": {
223 "ref": "bafkreixyz789banner",
224 "mimeType": "image/jpeg",
225 "size": 450000
226 }
227 }
228}
229```
230
231### Step 3: Update Profile
232
233```graphql
234mutation UpdateProfileWithImages {
235 updateAppBskyActorProfile(
236 rkey: "self"
237 input: {
238 displayName: "Alice Smith"
239 description: "Software engineer & designer"
240 avatar: {
241 ref: "bafkreiabc123avatar"
242 mimeType: "image/jpeg"
243 size: 125000
244 }
245 banner: {
246 ref: "bafkreixyz789banner"
247 mimeType: "image/jpeg"
248 size: 450000
249 }
250 }
251 ) {
252 uri
253 displayName
254 description
255 avatar {
256 ref
257 mimeType
258 size
259 url(preset: "avatar")
260 }
261 banner {
262 ref
263 mimeType
264 size
265 url(preset: "banner")
266 }
267 }
268}
269```
270
271Response:
272```json
273{
274 "data": {
275 "updateAppBskyActorProfile": {
276 "uri": "at://did:plc:xyz/app.bsky.actor.profile/self",
277 "displayName": "Alice Smith",
278 "description": "Software engineer & designer",
279 "avatar": {
280 "ref": "bafkreiabc123avatar",
281 "mimeType": "image/jpeg",
282 "size": 125000,
283 "url": "https://cdn.bsky.app/img/avatar/plain/did:plc:xyz/bafkreiabc123avatar@jpeg"
284 },
285 "banner": {
286 "ref": "bafkreixyz789banner",
287 "mimeType": "image/jpeg",
288 "size": 450000,
289 "url": "https://cdn.bsky.app/img/banner/plain/did:plc:xyz/bafkreixyz789banner@jpeg"
290 }
291 }
292 }
293}
294```
295
296## JavaScript Example
297
298```javascript
299// Convert file to base64
300async function fileToBase64(file) {
301 return new Promise((resolve, reject) => {
302 const reader = new FileReader();
303 reader.readAsDataURL(file);
304 reader.onload = () => {
305 const base64 = reader.result.split(',')[1]; // Remove data:image/jpeg;base64, prefix
306 resolve(base64);
307 };
308 reader.onerror = reject;
309 });
310}
311
312// Upload blob
313async function uploadBlob(file, token) {
314 const base64Data = await fileToBase64(file);
315
316 const response = await fetch('/graphql', {
317 method: 'POST',
318 headers: {
319 'Content-Type': 'application/json',
320 'Authorization': `Bearer ${token}`
321 },
322 body: JSON.stringify({
323 query: `
324 mutation UploadBlob($data: String!, $mimeType: String!) {
325 uploadBlob(data: $data, mimeType: $mimeType) {
326 ref
327 mimeType
328 size
329 }
330 }
331 `,
332 variables: {
333 data: base64Data,
334 mimeType: file.type
335 }
336 })
337 });
338
339 const result = await response.json();
340 return result.data.uploadBlob;
341}
342
343// Usage
344const avatarFile = document.getElementById('avatar-input').files[0];
345const blob = await uploadBlob(avatarFile, 'your-token');
346console.log('Uploaded blob:', blob.ref);
347```