Auto-indexing service and GraphQL API for AT Protocol Records
quickslice.slices.network/
atproto
gleam
graphql
1# Queries
2
3Quickslice generates a GraphQL query for each Lexicon record type at the `/graphql` endpoint. Queries are public; no authentication required.
4
5> **Endpoints:** Lexicon queries and mutations use `/graphql`. Admin operations (labels, reports, settings) use `/admin/graphql`.
6
7## Relay Connections
8
9Queries return data in the [Relay Connection](https://relay.dev/graphql/connections.htm) format:
10
11```graphql
12query {
13 xyzStatusphereStatus {
14 edges {
15 node {
16 uri
17 status
18 createdAt
19 }
20 cursor
21 }
22 pageInfo {
23 hasNextPage
24 endCursor
25 }
26 totalCount
27 }
28}
29```
30
31- `edges`: Array of results, each containing a `node` (the record) and `cursor` (for pagination)
32- `pageInfo`: Pagination metadata
33- `totalCount`: Total number of matching records
34
35## Built-in Fields
36
37Every record includes these fields automatically:
38
39| Field | Description |
40|-------|-------------|
41| `uri` | The AT-URI of the record |
42| `cid` | Content identifier (hash) |
43| `did` | Author's decentralized identifier |
44| `collection` | The Lexicon collection (e.g., `app.bsky.feed.post`) |
45| `actorHandle` | Author's handle (e.g., `alice.bsky.social`) |
46| `indexedAt` | When Quickslice indexed the record |
47
48The `actorHandle` field resolves the author's DID to their current handle, useful for display without a separate join:
49
50```graphql
51query {
52 xyzStatusphereStatus(first: 10) {
53 edges {
54 node {
55 status
56 actorHandle
57 }
58 }
59 }
60}
61```
62
63## Filtering
64
65Use the `where` argument to filter records:
66
67```graphql
68query {
69 xyzStatusphereStatus(where: { status: { eq: "🎉" } }) {
70 edges {
71 node {
72 status
73 createdAt
74 }
75 }
76 }
77}
78```
79
80### Filter Operators
81
82| Operator | Description | Example |
83|----------|-------------|---------|
84| `eq` | Equal to | `{ status: { eq: "👍" } }` |
85| `ne` | Not equal to | `{ status: { ne: "👎" } }` |
86| `in` | In array | `{ status: { in: ["👍", "🎉"] } }` |
87| `contains` | String contains (case-insensitive) | `{ displayName: { contains: "alice" } }` |
88| `gt` | Greater than | `{ createdAt: { gt: "2025-01-01T00:00:00Z" } }` |
89| `lt` | Less than | `{ createdAt: { lt: "2025-06-01T00:00:00Z" } }` |
90| `gte` | Greater than or equal | `{ position: { gte: 1 } }` |
91| `lte` | Less than or equal | `{ position: { lte: 10 } }` |
92| `isNull` | Null check | `{ reply: { isNull: true } }` |
93
94### Filtering Ref Fields
95
96Reference fields (AT-URIs or strong refs pointing to other records) only support `isNull`. Use it to find records with or without a reference:
97
98```graphql
99query {
100 # Find root posts (no reply)
101 appBskyFeedPost(where: { reply: { isNull: true } }) {
102 edges {
103 node {
104 text
105 }
106 }
107 }
108}
109```
110
111```graphql
112query {
113 # Find replies only
114 appBskyFeedPost(where: { reply: { isNull: false } }) {
115 edges {
116 node {
117 text
118 }
119 }
120 }
121}
122```
123
124### Multiple Conditions
125
126Combine multiple conditions (they're ANDed together):
127
128```graphql
129query {
130 appBskyActorProfile(where: {
131 displayName: { contains: "alice" }
132 createdAt: { gt: "2025-01-01T00:00:00Z" }
133 }) {
134 edges {
135 node {
136 displayName
137 description
138 }
139 }
140 }
141}
142```
143
144## Sorting
145
146Use `sortBy` to order results:
147
148```graphql
149query {
150 xyzStatusphereStatus(sortBy: [{ field: createdAt, direction: DESC }]) {
151 edges {
152 node {
153 status
154 createdAt
155 }
156 }
157 }
158}
159```
160
161### Multi-Field Sorting
162
163Sort by multiple fields (applied in order):
164
165```graphql
166query {
167 appBskyActorProfile(sortBy: [
168 { field: displayName, direction: ASC }
169 { field: createdAt, direction: DESC }
170 ]) {
171 edges {
172 node {
173 displayName
174 createdAt
175 }
176 }
177 }
178}
179```
180
181## Pagination
182
183### Forward Pagination
184
185Use `first` to limit results and `after` to get the next page:
186
187```graphql
188# First page
189query {
190 xyzStatusphereStatus(first: 10) {
191 edges {
192 node { status }
193 cursor
194 }
195 pageInfo {
196 hasNextPage
197 endCursor
198 }
199 }
200}
201
202# Next page (use endCursor from previous response)
203query {
204 xyzStatusphereStatus(first: 10, after: "cursor_from_previous_page") {
205 edges {
206 node { status }
207 cursor
208 }
209 pageInfo {
210 hasNextPage
211 endCursor
212 }
213 }
214}
215```
216
217### Backward Pagination
218
219Use `last` and `before` to paginate backward:
220
221```graphql
222query {
223 xyzStatusphereStatus(last: 10, before: "some_cursor") {
224 edges {
225 node { status }
226 cursor
227 }
228 pageInfo {
229 hasPreviousPage
230 startCursor
231 }
232 }
233}
234```
235
236### PageInfo Fields
237
238| Field | Description |
239|-------|-------------|
240| `hasNextPage` | More items exist after this page |
241| `hasPreviousPage` | More items exist before this page |
242| `startCursor` | Cursor of the first item |
243| `endCursor` | Cursor of the last item |
244
245## Complete Example
246
247Combining filtering, sorting, and pagination:
248
249```graphql
250query GetRecentStatuses($pageSize: Int!, $cursor: String) {
251 xyzStatusphereStatus(
252 where: { status: { in: ["👍", "🎉", "💙"] } }
253 sortBy: [{ field: createdAt, direction: DESC }]
254 first: $pageSize
255 after: $cursor
256 ) {
257 edges {
258 node {
259 uri
260 status
261 createdAt
262 }
263 cursor
264 }
265 pageInfo {
266 hasNextPage
267 endCursor
268 }
269 totalCount
270 }
271}
272```
273
274Variables:
275
276```json
277{
278 "pageSize": 20,
279 "cursor": null
280}
281```