Auto-indexing service and GraphQL API for AT Protocol Records
quickslice.slices.network/
atproto
gleam
graphql
1# Common Patterns
2
3Recipes for common use cases when building with Quickslice.
4
5## Profile Lookups
6
7Join author profiles to any record type to display names and avatars.
8
9```graphql
10query PostsWithAuthors {
11 myAppPost(first: 20, sortBy: [{ field: createdAt, direction: DESC }]) {
12 edges {
13 node {
14 content
15 createdAt
16 appBskyActorProfileByDid {
17 displayName
18 avatar { url(preset: "avatar") }
19 }
20 }
21 }
22 }
23}
24```
25
26The `appBskyActorProfileByDid` field works on all records because every record has a `did` field.
27
28## User Timelines
29
30Fetch all records by a specific user using DID joins from their profile.
31
32```graphql
33query UserTimeline($handle: String!) {
34 appBskyActorProfile(first: 1, where: { actorHandle: { eq: $handle } }) {
35 edges {
36 node {
37 displayName
38 myAppPostByDid(first: 20, sortBy: [{ field: createdAt, direction: DESC }]) {
39 edges {
40 node {
41 content
42 createdAt
43 }
44 }
45 }
46 }
47 }
48 }
49}
50```
51
52## Engagement Counts
53
54Use reverse joins with `totalCount` to show likes, comments, or other engagement metrics.
55
56```graphql
57query PhotosWithEngagement {
58 socialGrainPhoto(first: 10) {
59 edges {
60 node {
61 uri
62 alt
63 socialGrainFavoriteViaSubject {
64 totalCount
65 }
66 socialGrainCommentViaSubject {
67 totalCount
68 }
69 }
70 }
71 }
72}
73```
74
75## Feed with Nested Data
76
77Build a rich feed by combining multiple join types.
78
79```graphql
80query Feed {
81 myAppPost(first: 20, sortBy: [{ field: createdAt, direction: DESC }]) {
82 edges {
83 node {
84 uri
85 content
86 createdAt
87
88 # Author profile
89 appBskyActorProfileByDid {
90 displayName
91 avatar { url(preset: "avatar") }
92 }
93
94 # Engagement counts
95 myAppLikeViaSubject {
96 totalCount
97 }
98 myAppCommentViaSubject {
99 totalCount
100 }
101
102 # Preview of recent comments
103 myAppCommentViaSubject(first: 3, sortBy: [{ field: createdAt, direction: DESC }]) {
104 edges {
105 node {
106 text
107 appBskyActorProfileByDid {
108 displayName
109 }
110 }
111 }
112 }
113 }
114 }
115 }
116}
117```
118
119## Paginated Lists
120
121Implement infinite scroll or "load more" with cursor-based pagination.
122
123```graphql
124query PaginatedStatuses($cursor: String) {
125 xyzStatusphereStatus(
126 first: 20
127 after: $cursor
128 sortBy: [{ field: createdAt, direction: DESC }]
129 ) {
130 edges {
131 node {
132 status
133 createdAt
134 }
135 }
136 pageInfo {
137 hasNextPage
138 endCursor
139 }
140 }
141}
142```
143
144First request: `{ "cursor": null }`
145
146Subsequent requests: `{ "cursor": "endCursor_from_previous_response" }`
147
148Continue until `hasNextPage` is `false`.
149
150## Filtered Search
151
152Combine multiple filters for search functionality.
153
154```graphql
155query SearchProfiles($query: String!) {
156 appBskyActorProfile(
157 first: 20
158 where: { displayName: { contains: $query } }
159 sortBy: [{ field: displayName, direction: ASC }]
160 ) {
161 edges {
162 node {
163 actorHandle
164 displayName
165 description
166 avatar { url(preset: "avatar") }
167 }
168 }
169 }
170}
171```
172
173## Date Range Queries
174
175Filter records within a time period.
176
177```graphql
178query RecentActivity($since: DateTime!, $until: DateTime!) {
179 myAppPost(
180 where: {
181 createdAt: { gte: $since, lt: $until }
182 }
183 sortBy: [{ field: createdAt, direction: DESC }]
184 ) {
185 edges {
186 node {
187 content
188 createdAt
189 }
190 }
191 totalCount
192 }
193}
194```
195
196Variables:
197```json
198{
199 "since": "2025-01-01T00:00:00Z",
200 "until": "2025-02-01T00:00:00Z"
201}
202```
203
204## Current User's Data
205
206Use the `viewer` query to get the authenticated user's records.
207
208```graphql
209query MyProfile {
210 viewer {
211 did
212 handle
213 appBskyActorProfileByDid {
214 displayName
215 description
216 avatar { url(preset: "avatar") }
217 }
218 myAppPostByDid(first: 10, sortBy: [{ field: createdAt, direction: DESC }]) {
219 totalCount
220 edges {
221 node {
222 content
223 createdAt
224 }
225 }
226 }
227 }
228}
229```
230
231## Real-Time Updates
232
233Subscribe to new records and update your UI live.
234
235```graphql
236subscription NewStatuses {
237 xyzStatusphereStatusCreated {
238 uri
239 status
240 createdAt
241 appBskyActorProfileByDid {
242 displayName
243 avatar { url(preset: "avatar") }
244 }
245 }
246}
247```
248
249Combine with an initial query to show existing data, then append new records as they arrive via subscription.
250
251## Aggregations
252
253Get statistics like top items or activity over time.
254
255```graphql
256query TopArtists($user: String!) {
257 fmTealAlphaFeedPlayAggregated(
258 groupBy: [{ field: artists }]
259 where: { actorHandle: { eq: $user } }
260 orderBy: { count: DESC }
261 limit: 10
262 ) {
263 artists
264 count
265 }
266}
267```
268
269```graphql
270query MonthlyActivity($user: String!) {
271 myAppPostAggregated(
272 groupBy: [{ field: createdAt, interval: MONTH }]
273 where: { actorHandle: { eq: $user } }
274 orderBy: { count: DESC }
275 ) {
276 createdAt
277 count
278 }
279}
280```