Auto-indexing service and GraphQL API for AT Protocol Records
quickslice.slices.network/
atproto
gleam
graphql
1import database/executor.{type Executor}
2import gleam/erlang/process.{type Subject}
3import gleam/json
4import gleam/option.{type Option}
5import gleam/result
6import graphql/lexicon/schema as lexicon_schema
7import lib/oauth/did_cache
8
9/// Execute a GraphQL query
10pub fn execute_query(
11 db: Executor,
12 query: String,
13 variables_json: String,
14 did_cache: Subject(did_cache.Message),
15 signing_key: Option(String),
16 plc_url: String,
17) -> Result(json.Json, String) {
18 use result_str <- result.try(lexicon_schema.execute_query_with_db(
19 db,
20 query,
21 variables_json,
22 Error(Nil),
23 // No auth token for MCP queries
24 did_cache,
25 signing_key,
26 "",
27 // Empty atp_client_id - MCP queries don't do mutations that need ATP refresh
28 plc_url,
29 ))
30
31 // Return the result string wrapped in a JSON object
32 Ok(json.object([#("result", json.string(result_str))]))
33}
34
35/// Get full GraphQL schema introspection
36pub fn introspect_schema(
37 db: Executor,
38 did_cache: Subject(did_cache.Message),
39 signing_key: Option(String),
40 plc_url: String,
41) -> Result(json.Json, String) {
42 let introspection_query =
43 "
44 query IntrospectionQuery {
45 __schema {
46 queryType { name }
47 mutationType { name }
48 subscriptionType { name }
49 types {
50 name
51 kind
52 description
53 fields {
54 name
55 description
56 args { name type { name } }
57 type { name kind ofType { name kind } }
58 }
59 }
60 }
61 }
62 "
63
64 execute_query(db, introspection_query, "{}", did_cache, signing_key, plc_url)
65}