agentsclimarketplace

Graphql for mobile

Skill almasumdev/awesome-mobile-backend-agent-skills/.github/skills/api/graphql-for-mobile

Agent skills for the backend-for-mobile layer: APIs, auth, push, sync, and BaaS integrations.

Install
npx -y skills add almasumdev/awesome-mobile-backend-agent-skills --skill graphql-for-mobile

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

GraphQL server design tuned for mobile -- persisted queries, batching, N+1 mitigation, and Apollo client integration. Use when building or reviewing a GraphQL API for mobile apps.

SKILL.md

5.1 KB, as published. Nobody here has run it

GraphQL for Mobile

Instructions

GraphQL's value for mobile is tight payload shaping and cross-resource composition in one round-trip. Its risks are unbounded queries, N+1 database loads, and shipping raw queries from the app. Mitigate all three.

1. Schema Design

Favor a graph of small, stable types over RPC-style fields.

type Article {
  id: ID!
  title: String!
  summary: String
  author: User!
  comments(first: Int = 20, after: String): CommentConnection!
  publishedAt: DateTime!
}

type Query {
  article(id: ID!): Article
  feed(first: Int = 20, after: String, filter: FeedFilter): ArticleConnection!
}

Use Relay-style connections (Connection, Edge, PageInfo) for all lists. Cursors are opaque, page size defaults to 20, maxes at 100.

2. Persisted Queries

Do not let the mobile client send arbitrary GraphQL strings in production. Use persisted queries: at build time, every query is hashed and registered on the server; the app sends only the hash.

POST /graphql
{"id": "sha256:ab12...", "variables": {"id": "a_1"}}

Benefits: smaller requests, query allowlisting, CDN-cacheable reads (GET with hash), no accidental schema exploration from shipped binaries.

Apollo iOS / Apollo Kotlin generate persisted IDs via their build plugins; wire them into the pipeline.

3. N+1 Mitigation with Dataloader

Resolvers that fetch child objects trigger one DB hit per parent unless batched.

// Node/TS with dataloader
const userLoader = new DataLoader<string, User>(async (ids) => {
  const users = await db.users.findMany({ where: { id: { in: ids as string[] } } });
  const byId = new Map(users.map(u => [u.id, u]));
  return ids.map(id => byId.get(id)!);
});

const resolvers = {
  Article: {
    author: (article, _, ctx) => ctx.loaders.user.load(article.authorId),
  },
};

Every request builds a fresh loader set (never share across requests -- caches must not leak between users).

4. Query Cost and Depth Limits

Reject expensive queries before resolving them.

  • Max depth: 8–10. Reject deeper.
  • Max complexity: compute a weighted cost (lists multiply by first).
  • Max aliases / duplicate fields: cap to prevent amplification attacks.

Libraries: graphql-depth-limit, graphql-query-complexity (Node); graphql-java cost analyzer.

5. Mutations

Mutations take a single input object and return a typed payload with a result union or an errors list:

input CreateCommentInput { articleId: ID!, body: String!, clientMutationId: String }
type CreateCommentPayload { comment: Comment, userErrors: [UserError!]! }

type Mutation { createComment(input: CreateCommentInput!): CreateCommentPayload! }

userErrors surfaces validation errors without failing the whole HTTP request. HTTP 200 is returned; only infrastructure failures become non-200. Include clientMutationId to pair optimistic UI updates with server responses.

6. Subscriptions

Prefer WebSockets (graphql-ws) for realtime. Keep subscription payloads small and resumable via a lastEventId. For most mobile apps, polling or periodic refetch is simpler than subscriptions -- reach for subs only when sub-second latency matters (chat, live scores, collaborative edit).

7. Caching

  • HTTP-level: persisted-query GETs are CDN-cacheable by query hash + variables hash.
  • Client-level: Apollo Normalized Cache keyed by __typename:id. Every type that can appear in multiple queries must expose id and __typename.
  • Ensure stable id fields; never reuse ids across types without a composite key.

8. Apollo Client on Mobile

Apollo Kotlin (Android):

val apollo = ApolloClient.Builder()
  .serverUrl("https://api.example.com/graphql")
  .autoPersistedQueries() // sends hash first, falls back to full query once
  .normalizedCache(MemoryCacheFactory(maxSizeBytes = 10 * 1024 * 1024))
  .addHttpInterceptor(AuthHeaderInterceptor(tokenStore))
  .build()

val feed = apollo.query(FeedQuery(first = 20)).fetchPolicy(FetchPolicy.CacheAndNetwork).execute()

Apollo iOS has an equivalent API (ApolloClient, NormalizedCache, RequestChainNetworkTransport).

9. Error Handling

GraphQL returns 200 even for partial failures. The client must inspect both errors (top-level GraphQL errors) and data. Map stable error codes through extensions.code so clients can act (UNAUTHENTICATED, RATE_LIMITED, VALIDATION_FAILED).

Checklist

  • Relay-style connections for every list field with default/max page sizes.
  • Persisted queries enforced in production; raw queries rejected.
  • Dataloader (or equivalent) batching for every parent-to-child field.
  • Depth and complexity limits enabled and tested.
  • Mutations follow input / payload + userErrors pattern.
  • Every cacheable type exposes id + __typename.
  • Error codes in extensions.code are stable and documented.
  • Apollo client configured with auth interceptor, cache size, and fetch policy.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.