zuplo 6.71.20 → 6.71.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,96 @@
1
+ ---
2
+ title: Cache GraphQL responses with Zuplo
3
+ sidebar_label: Cache responses
4
+ description:
5
+ Serve repeated GraphQL queries from the edge with the GraphQL Cache policy to
6
+ cut latency and reduce load on your origin.
7
+ tags:
8
+ - caching
9
+ - backends
10
+ ---
11
+
12
+ GraphQL clients send queries as POST request bodies, so a normal CDN — which
13
+ keys on the URL — can't cache them. The
14
+ [`graphql-cache-inbound`](../policies/graphql-cache-inbound.mdx) policy solves
15
+ this: it parses each query, normalizes it into a canonical form, and caches the
16
+ response in a [ZoneCache](../programmable-api/zone-cache.mdx) at the edge. Two
17
+ requests that are semantically identical share a cache entry even when their
18
+ bodies differ byte-for-byte.
19
+
20
+ Only `query` operations are cached. Mutations, subscriptions, malformed
21
+ documents, and responses that contain GraphQL `errors` are always forwarded to
22
+ your origin untouched.
23
+
24
+ ## Add the cache policy
25
+
26
+ Add `graphql-cache-inbound` to the inbound policies of your GraphQL route.
27
+
28
+ <Stepper>
29
+
30
+ 1. **Open `policies.json`**
31
+
32
+ In the Zuplo Portal, open the **Code** tab and add the policy definition:
33
+
34
+ ```json title="config/policies.json"
35
+ {
36
+ "name": "graphql-cache",
37
+ "policyType": "graphql-cache-inbound",
38
+ "handler": {
39
+ "export": "GraphQLCacheInboundPolicy",
40
+ "module": "$import(@zuplo/graphql)",
41
+ "options": {
42
+ "cacheName": "graphql-responses",
43
+ "ttlSeconds": 60
44
+ }
45
+ }
46
+ }
47
+ ```
48
+
49
+ 2. **Attach it to your GraphQL route**
50
+
51
+ Add `"graphql-cache"` to the route's inbound policies in `routes.oas.json`,
52
+ ahead of any policy that rewrites the request.
53
+
54
+ 3. **Verify the cache is working**
55
+
56
+ Send the same query twice and inspect the response headers. The policy adds
57
+ `x-cache: MISS` on the first request and `x-cache: HIT` on the second. The
58
+ `x-cache-key` header (first 8 characters of the cache key) confirms two
59
+ requests resolve to the same entry.
60
+
61
+ </Stepper>
62
+
63
+ ## Cache authenticated traffic safely
64
+
65
+ By default, requests that carry an `authorization` or `cookie` header are
66
+ **not** cached — otherwise the first user's response would be served to
67
+ everyone. To cache per-user, list the headers that make a response user-specific
68
+ in `cacheKeyHeaders`. Each distinct value gets its own entry:
69
+
70
+ ```json title="config/policies.json"
71
+ {
72
+ "options": {
73
+ "ttlSeconds": 30,
74
+ "cacheKeyHeaders": ["authorization"]
75
+ }
76
+ }
77
+ ```
78
+
79
+ :::caution
80
+
81
+ Setting `cacheKeyHeaders` to an empty array `[]` caches a single response and
82
+ shares it across all callers. Only do this when the response genuinely doesn't
83
+ depend on who is calling — otherwise one caller's data leaks to others.
84
+
85
+ :::
86
+
87
+ See the [GraphQL Cache policy reference](../policies/graphql-cache-inbound.mdx)
88
+ for the full option matrix, including how credentialed requests fail safe.
89
+
90
+ ## Next steps
91
+
92
+ - [Secure your GraphQL API](./graphql-security.mdx) — complexity limits and
93
+ introspection controls
94
+ - [GraphQL on Zuplo](./graphql.mdx) — set up the endpoint and Dev Portal docs
95
+ - [GraphQL analytics](../analytics/tabs/graphql.md) — watch hit rates and
96
+ latency once traffic flows
@@ -2,179 +2,190 @@
2
2
  title: Secure your GraphQL API with Zuplo
3
3
  sidebar_label: Secure your GraphQL API
4
4
  description:
5
- Learn how to secure your GraphQL API using Zuplo's security policies to
6
- prevent DoS attacks and protect schema information.
5
+ Protect your GraphQL API from denial-of-service attacks and schema discovery
6
+ using Zuplo's GraphQL security policies.
7
7
  tags:
8
8
  - authentication
9
9
  - backends
10
10
  ---
11
11
 
12
- **Secure your GraphQL API with Zuplo**
12
+ GraphQL gives clients enormous flexibility over what they ask for — which is
13
+ also what makes it easy to abuse. A single request can nest arbitrarily deep,
14
+ fan out into thousands of resolver calls, or map your entire schema through
15
+ introspection. Zuplo ships three policies that close these gaps at the edge,
16
+ before a malicious request ever reaches your origin:
13
17
 
14
- GraphQL is a powerful query language for your APIs. While it offers great
15
- flexibility for clients, it also exposes potential security risks. Fortunately,
16
- with Zuplo, you can secure your GraphQL API by implementing various policies.
17
- This article walks you through our security policies:
18
- [GraphQL Complexity Limit](/docs/policies/graphql-complexity-limit-inbound), and
19
- [GraphQL Disable Introspection](/docs/policies/graphql-disable-introspection-inbound).
18
+ | Risk | Policy |
19
+ | ------------------- | ------------------------------------------------------------------------------------------------ |
20
+ | Deep / costly query | [`graphql-complexity-limit-inbound`](../policies/graphql-complexity-limit-inbound.mdx) |
21
+ | Schema discovery | [`graphql-disable-introspection-inbound`](../policies/graphql-disable-introspection-inbound.mdx) |
22
+ | Schema over-sharing | [`graphql-introspection-filter-outbound`](../policies/graphql-introspection-filter-outbound.mdx) |
20
23
 
21
- ## 1. Understanding the Risks
24
+ This guide explains each risk and shows the policy configuration that addresses
25
+ it. It assumes you've already
26
+ [added a GraphQL endpoint to your gateway](./graphql.mdx).
22
27
 
23
- ### a. Deeply Nested Queries
28
+ ## Understand the risks
24
29
 
25
- Without restrictions, a client can send deeply nested queries that could
26
- potentially overwhelm your server, resulting in a Denial of Service (DoS)
27
- attack. This is because deeply nested queries can cause the server to process a
28
- huge amount of data and operations. While this might be a planned attack, it
29
- could also be a mistake by a client who is unaware of the query depth limit.
30
+ ### Deeply nested or expensive queries
30
31
 
31
- ### b. Query Complexity
32
+ Without limits, a client can send a deeply nested query that forces your server
33
+ to resolve a huge graph of data, or a flat-but-expensive query that triggers
34
+ thousands of resolver calls. Either can exhaust resources and cause a
35
+ denial-of-service — whether the client is a deliberate attacker or simply
36
+ unaware of the cost of their query.
32
37
 
33
- Even without deep nesting, a query can be crafted to be very complex. This could
34
- force your server to execute resource-intensive operations, potentially slowing
35
- down the system or causing a DoS.
38
+ ### Introspection
36
39
 
37
- ### c. Introspection
40
+ GraphQL lets clients introspect your schema with `__schema` and `__type`
41
+ queries. This is invaluable during development, but in production it hands
42
+ potential attackers a complete map of your types, fields, and relationships.
38
43
 
39
- GraphQL allows clients to introspect your schema. While this is beneficial
40
- during development, it can expose detailed schema information to potential
41
- attackers in production.
44
+ ## Limit query depth and complexity
42
45
 
43
- ## 2. Add your GraphQL API & setting up Policies
46
+ The
47
+ [`graphql-complexity-limit-inbound`](../policies/graphql-complexity-limit-inbound.mdx)
48
+ policy guards against expensive queries in two complementary ways. You can use
49
+ either or both.
44
50
 
45
- ### Set Up POST Endpoint
51
+ ### Depth limit
46
52
 
47
- If you didn't already do so, you need to set up a POST endpoint in your API.
48
- This endpoint will be used to send the GraphQL queries to your API. The
49
- urlRewriteHandler to rewrite the request to your GraphQL API. For this example
50
- let's assume your GraphQL API is hosted at `https://api.example.com/graphql`.
53
+ A depth limit caps how many levels a query can nest. It needs no schema and is
54
+ the simplest first line of defense. Add it under `useDepthLimit`:
51
55
 
52
- To do so, add the following to your `config/routes.oas.json`
53
-
54
- ```json
56
+ ```json title="config/policies.json"
55
57
  {
56
- "post": {
57
- "summary": "GraphQL Query",
58
- "description": "The endpoint for GraphQL queries.",
59
- "x-zuplo-route": {
60
- "corsPolicy": "none",
61
- "handler": {
62
- "export": "urlRewriteHandler",
63
- "module": "$import(@zuplo/runtime)",
64
- "options": {
65
- "rewritePattern": "https://api.example.com/graphql"
66
- }
67
- },
68
- "policies": {
69
- "inbound": [
70
- "graphql-complexity-limit-policy",
71
- "graphql-disable-introspection-policy"
72
- ]
58
+ "name": "graphql-complexity-limit-policy",
59
+ "policyType": "graphql-complexity-limit-inbound",
60
+ "handler": {
61
+ "export": "GraphQLComplexityLimitInboundPolicy",
62
+ "module": "$import(@zuplo/graphql)",
63
+ "options": {
64
+ "useDepthLimit": {
65
+ "depthLimit": 20
73
66
  }
74
- },
75
- "operationId": "52bdf225-eaa7-441c-afb9-b7df046a142e"
67
+ }
76
68
  }
77
69
  }
78
70
  ```
79
71
 
80
- For all the risks mentioned above, Zuplo offers policies that can be configured
81
- to protect your GraphQL API. These policies can be configured for Zuplo. We'll
82
- create the configuration for the three policies `graphql-depth-limit`,
83
- `graphql-complexity-points` and `graphql-disable-introspection-policy` next.
72
+ ### Complexity limit
84
73
 
85
- ### a. GraphQL Depth Limit
74
+ A complexity limit scores each query against your schema and rejects queries
75
+ above a threshold, catching expensive queries that aren't necessarily deep.
76
+ Because it scores against the schema, it needs your GraphQL endpoint URL for
77
+ introspection. Combine it with the depth limit:
86
78
 
87
- This policy limits how deep a query can be nested. Check our
88
- [detailed policy documentation](/docs/policies/graphql-complexity-limit-inbound)
89
- for more information.
90
-
91
- Add this into your `config/policies.json`
92
-
93
- ```json
79
+ ```json title="config/policies.json"
94
80
  {
95
- "policies": [
96
- {
97
- "name": "graphql-complexity-limit-policy",
98
- "policyType": "graphql-complexity-limit-inbound",
99
- "handler": {
100
- "export": "GraphQLComplexityLimitInboundPolicy",
101
- "module": "$import(@zuplo/graphql)",
102
- "options": {
103
- "useDepthLimit": {
104
- "depthLimit": 20
105
- }
106
- }
81
+ "name": "graphql-complexity-limit-policy",
82
+ "policyType": "graphql-complexity-limit-inbound",
83
+ "handler": {
84
+ "export": "GraphQLComplexityLimitInboundPolicy",
85
+ "module": "$import(@zuplo/graphql)",
86
+ "options": {
87
+ "useDepthLimit": {
88
+ "depthLimit": 20
89
+ },
90
+ "useComplexityLimit": {
91
+ "complexityLimit": 50,
92
+ "endpointUrl": "https://api.example.com/graphql"
107
93
  }
108
94
  }
109
- ]
95
+ }
110
96
  }
111
97
  ```
112
98
 
113
- By limiting the query depth, you prevent malicious or mistakenly deep queries
114
- from consuming excessive server resources.
99
+ A query that exceeds either limit is rejected with a `400` and a GraphQL error;
100
+ requests within the limits pass through. See the
101
+ [policy reference](../policies/graphql-complexity-limit-inbound.mdx) for the
102
+ full option set.
115
103
 
116
- ### b. GraphQL Complexity Limit
104
+ ## Disable introspection in production
117
105
 
118
- We can extend the same policy to also check for complexity. By defining a max
119
- for each type of operation, and then it limits the total complexity a query can
120
- have. In order to use the Complexity Limit you need to allow introspection in
121
- your GraphQL API.
106
+ The
107
+ [`graphql-disable-introspection-inbound`](../policies/graphql-disable-introspection-inbound.mdx)
108
+ policy blocks any query containing `__schema` or `__type` with a `403`, hiding
109
+ your schema from clients. It takes no options:
122
110
 
123
- ```json
111
+ ```json title="config/policies.json"
124
112
  {
125
- "policies": [
126
- {
127
- "name": "graphql-complexity-limit-policy",
128
- "policyType": "graphql-complexity-limit-inbound",
129
- "handler": {
130
- "export": "GraphQLComplexityLimitInboundPolicy",
131
- "module": "$import(@zuplo/graphql)",
132
- "options": {
133
- "useDepthLimit": {
134
- "depthLimit": 20
135
- },
136
- "useComplexityLimit": {
137
- "complexityLimit": 50,
138
- "endpointUrl": "https://api.example.com/graphql"
139
- }
140
- }
113
+ "name": "graphql-disable-introspection-policy",
114
+ "policyType": "graphql-disable-introspection-inbound",
115
+ "handler": {
116
+ "export": "GraphQLDisableIntrospectionInboundPolicy",
117
+ "module": "$import(@zuplo/graphql)",
118
+ "options": {}
119
+ }
120
+ }
121
+ ```
122
+
123
+ ## Expose a partial schema instead
124
+
125
+ Disabling introspection entirely isn't always what you want. If you need clients
126
+ (or [MCP-connected AI agents](../mcp-server/graphql.mdx)) to introspect part of
127
+ your schema while keeping sensitive types and fields hidden, use the outbound
128
+ [`graphql-introspection-filter-outbound`](../policies/graphql-introspection-filter-outbound.mdx)
129
+ policy. It strips chosen types and fields from introspection responses:
130
+
131
+ ```json title="config/policies.json"
132
+ {
133
+ "name": "graphql-introspection-filter-policy",
134
+ "policyType": "graphql-introspection-filter-outbound",
135
+ "handler": {
136
+ "export": "GraphQLIntrospectionFilterOutboundPolicy",
137
+ "module": "$import(@zuplo/graphql)",
138
+ "options": {
139
+ "excludeTypes": ["AdminUser"],
140
+ "excludeTypeFields": {
141
+ "User": ["password", "ssn"],
142
+ "Query": ["adminUsers"]
141
143
  }
142
144
  }
143
- ]
145
+ }
144
146
  }
145
147
  ```
146
148
 
147
- The complexity limit ensures that a potential attacker can't overload the system
148
- by sending overly complicated queries.
149
-
150
- ### c. GraphQL Disable Introspection
149
+ ## Attach the policies to your route
151
150
 
152
- Disable introspection in production environments to hide schema details.
151
+ Add the inbound policies to your GraphQL route in `routes.oas.json`. The
152
+ outbound filter policy goes in the `outbound` array:
153
153
 
154
- ```json
154
+ ```json title="config/routes.oas.json"
155
155
  {
156
- "policies": [
157
- {
158
- "name": "graphql-disable-introspection-policy",
159
- "policyType": "graphql-disable-introspection-inbound",
156
+ "post": {
157
+ "summary": "GraphQL Endpoint",
158
+ "x-graphql": true,
159
+ "x-zuplo-route": {
160
+ "corsPolicy": "none",
160
161
  "handler": {
161
- "export": "GraphQLDisableIntrospectionInboundPolicy",
162
- "module": "$import(@zuplo/graphql)",
163
- "options": {}
162
+ "export": "urlRewriteHandler",
163
+ "module": "$import(@zuplo/runtime)",
164
+ "options": {
165
+ "rewritePattern": "https://api.example.com/graphql"
166
+ }
167
+ },
168
+ "policies": {
169
+ "inbound": [
170
+ "graphql-complexity-limit-policy",
171
+ "graphql-disable-introspection-policy"
172
+ ]
164
173
  }
165
- }
166
- ]
174
+ },
175
+ "operationId": "graphql-secure"
176
+ }
167
177
  }
168
178
  ```
169
179
 
170
- By disabling introspection in production, you prevent attackers from gaining
171
- insights into your GraphQL schema, thereby reducing potential attack vectors.
180
+ ## Example repository
181
+
182
+ For a complete, runnable setup, see the
183
+ [GraphQL API with Zuplo example repository](https://github.com/zuplo/zuplo-graphql-example).
172
184
 
173
- ## 4. Example Repository
185
+ ## Next steps
174
186
 
175
- For those who prefer a hands-on approach or wish to see these configurations in
176
- action, there is a GitHub repository with everything set up. This repository
177
- offers a comprehensive example of how to configure and secure a GraphQL API
178
- using Zuplo. Check out the
179
- [GraphQL API with Zuplo example repository](https://github.com/zuplo/zuplo-graphql-example)
180
- to dive deeper.
187
+ - [Cache GraphQL responses](./graphql-caching.mdx) cut latency with edge
188
+ caching
189
+ - [Test GraphQL queries](./testing-graphql.mdx) verify your secured endpoint
190
+ - [GraphQL analytics](../analytics/tabs/graphql.md) surface errors and monitor
191
+ traffic
@@ -0,0 +1,107 @@
1
+ ---
2
+ title: GraphQL support on Zuplo
3
+ sidebar_label: Overview
4
+ description:
5
+ Everything Zuplo supports for GraphQL APIs — proxying, security, caching,
6
+ analytics, Dev Portal docs, and MCP — with links to each guide and policy.
7
+ tags:
8
+ - backends
9
+ ---
10
+
11
+ Zuplo treats GraphQL as a first-class backend. Proxy your existing GraphQL
12
+ server through the gateway, then layer on security, caching, analytics, and
13
+ documentation using policies built for the GraphQL request shape — where every
14
+ operation is a `POST` to a single URL, so URL-based gateway features don't
15
+ apply.
16
+
17
+ This page summarizes what Zuplo supports for GraphQL and links to each guide and
18
+ policy reference.
19
+
20
+ :::tip{title="New here?"}
21
+
22
+ Start with [Set up an endpoint](./graphql.mdx) to proxy your GraphQL API through
23
+ the gateway, then come back to layer on the capabilities below.
24
+
25
+ :::
26
+
27
+ ## Connect and route
28
+
29
+ Proxy any GraphQL server through a `POST /graphql` route using the
30
+ [URL Rewrite handler](../handlers/url-rewrite.mdx). The Route Designer ships a
31
+ **GraphQL Endpoint** template, and the `x-graphql` route extension marks a route
32
+ as GraphQL so the gateway and Dev Portal treat it accordingly.
33
+
34
+ - [Set up an endpoint](./graphql.mdx) — add or mark a GraphQL route
35
+
36
+ ## Secure the endpoint
37
+
38
+ GraphQL's flexibility is also its attack surface: a single request can nest
39
+ arbitrarily deep, fan out into thousands of resolver calls, or map your whole
40
+ schema through introspection. Zuplo closes these gaps at the edge.
41
+
42
+ | Risk | What Zuplo does |
43
+ | ------------------- | ------------------------------------------------ |
44
+ | Deep / costly query | Reject queries over a depth or complexity score |
45
+ | Schema discovery | Block introspection in production |
46
+ | Schema over-sharing | Strip chosen types and fields from introspection |
47
+
48
+ - [Secure your GraphQL API](./graphql-security.mdx) — complexity limits and
49
+ introspection controls
50
+
51
+ ## Accelerate with caching
52
+
53
+ A normal CDN keys on the URL, so it can't cache GraphQL queries sent as request
54
+ bodies. The GraphQL cache parses each query, normalizes it into a canonical
55
+ form, and serves semantically identical queries from one edge cache entry.
56
+
57
+ - [Cache GraphQL responses](./graphql-caching.mdx) — serve repeated queries from
58
+ the edge
59
+
60
+ ## Observe traffic
61
+
62
+ Report GraphQL operations and their errors to analytics, even when the upstream
63
+ returns errors inside a `200` response. The GraphQL analytics dashboard surfaces
64
+ operation volume, latency, and error classes once traffic flows.
65
+
66
+ - [GraphQL analytics](../analytics/tabs/graphql.md) — monitor operations,
67
+ latency, and errors
68
+
69
+ ## Document in the Dev Portal
70
+
71
+ The `@zudoku/plugin-graphql` package renders a browsable type reference and an
72
+ interactive playground in your Dev Portal, generated from your schema or a live
73
+ endpoint. Register one instance per API.
74
+
75
+ - [Document the API in your Dev Portal](./graphql.mdx#document-the-api-in-your-dev-portal)
76
+ — add the GraphQL plugin
77
+
78
+ ## Expose GraphQL to AI agents
79
+
80
+ Turn GraphQL queries into MCP tools so AI agents can call your API through the
81
+ Model Context Protocol, with the same policies and auth applied.
82
+
83
+ - [MCP Server GraphQL endpoints](../mcp-server/graphql.mdx) — expose queries as
84
+ MCP tools
85
+
86
+ ## Policies at a glance
87
+
88
+ Every GraphQL-aware policy Zuplo ships, with its direction and purpose:
89
+
90
+ | Policy | Direction | Purpose |
91
+ | ------------------------------------------------------------------------------------------------ | --------- | ------------------------------------------------- |
92
+ | [`graphql-cache-inbound`](../policies/graphql-cache-inbound.mdx) | Inbound | Cache repeated queries at the edge |
93
+ | [`graphql-complexity-limit-inbound`](../policies/graphql-complexity-limit-inbound.mdx) | Inbound | Reject queries that are too deep or too expensive |
94
+ | [`graphql-disable-introspection-inbound`](../policies/graphql-disable-introspection-inbound.mdx) | Inbound | Block schema introspection in production |
95
+ | [`graphql-introspection-filter-outbound`](../policies/graphql-introspection-filter-outbound.mdx) | Outbound | Hide chosen types and fields from introspection |
96
+ | [`graphql-analytics-outbound`](../policies/graphql-analytics-outbound.mdx) | Outbound | Report operations and errors to analytics |
97
+
98
+ ## Next steps
99
+
100
+ - [Set up an endpoint](./graphql.mdx) — proxy your GraphQL API through the
101
+ gateway
102
+ - [Secure your GraphQL API](./graphql-security.mdx) — complexity limits and
103
+ introspection controls
104
+ - [Cache GraphQL responses](./graphql-caching.mdx) — cut latency with edge
105
+ caching
106
+ - [MCP Server GraphQL endpoints](../mcp-server/graphql.mdx) — expose queries to
107
+ AI agents
@@ -18,6 +18,7 @@ your schema in the Dev Portal. This guide walks you through setting it up.
18
18
  Rewrite handler
19
19
  - [ ] Tag the route with the `x-graphql` extension
20
20
  - [ ] Surface failed operations with the `graphql-analytics-outbound` policy
21
+ - [ ] Add caching and security policies to protect and accelerate the endpoint
21
22
  - [ ] Add the `graphqlPlugin` to the Developer Portal
22
23
 
23
24
  :::
@@ -111,6 +112,23 @@ To fine-tune analytics, see the
111
112
  [GraphQL Analytics policy reference](../policies/graphql-analytics-outbound.mdx)
112
113
  for the full set of options.
113
114
 
115
+ ## Protect and accelerate the endpoint
116
+
117
+ Once requests are flowing, attach GraphQL-aware policies to the route. Zuplo
118
+ ships a set built specifically for the GraphQL request shape:
119
+
120
+ | Goal | Policy |
121
+ | ------------------------------------------ | ------------------------------------------------------------------------------------------------ |
122
+ | Cache repeated queries at the edge | [`graphql-cache-inbound`](../policies/graphql-cache-inbound.mdx) |
123
+ | Block deep or expensive queries | [`graphql-complexity-limit-inbound`](../policies/graphql-complexity-limit-inbound.mdx) |
124
+ | Disable schema introspection in production | [`graphql-disable-introspection-inbound`](../policies/graphql-disable-introspection-inbound.mdx) |
125
+ | Hide sensitive types from introspection | [`graphql-introspection-filter-outbound`](../policies/graphql-introspection-filter-outbound.mdx) |
126
+ | Report failed operations to analytics | [`graphql-analytics-outbound`](../policies/graphql-analytics-outbound.mdx) |
127
+
128
+ See [Secure your GraphQL API](./graphql-security.mdx) for the complexity and
129
+ introspection policies, and [Cache GraphQL responses](./graphql-caching.mdx) to
130
+ serve identical queries from the edge.
131
+
114
132
  ## Document the API in your Dev Portal
115
133
 
116
134
  The `@zudoku/plugin-graphql` package renders a browsable type reference and a
@@ -161,6 +179,8 @@ the playground is pointed at the right endpoint.
161
179
 
162
180
  - [Secure your GraphQL API](./graphql-security.mdx) — complexity limits and
163
181
  introspection policies
182
+ - [Cache GraphQL responses](./graphql-caching.mdx) — serve repeated queries from
183
+ the edge
164
184
  - [Testing GraphQL queries](./testing-graphql.mdx) — test the endpoint from the
165
185
  Zuplo Portal or external tools
166
186
  - [GraphQL analytics](../analytics/tabs/graphql.md) — monitor operation volume,
@@ -56,8 +56,8 @@ page for product-focused portals. The previews on this page are presented in a
56
56
  title="Build with our API"
57
57
  description="Everything you need to integrate payments, webhooks, and more — in minutes, not days."
58
58
  actions={[
59
- { label: "Get started", href: "/docs/getting-started" },
60
- { label: "API Reference", href: "/docs", variant: "outline" },
59
+ { label: "Get started", href: "/getting-started" },
60
+ { label: "API Reference", href: "/", variant: "outline" },
61
61
  ]}
62
62
  features={[
63
63
  {
@@ -121,7 +121,7 @@ front.
121
121
  title="Ship anywhere in the whole universe"
122
122
  description="Create and manage shipments, track packages in real-time, and integrate with multiple carriers through a single interface."
123
123
  actions={[
124
- { label: "Get started", href: "/docs/getting-started" },
124
+ { label: "Get started", href: "/getting-started" },
125
125
  { label: "View on GitHub", href: "https://github.com/zuplo/zudoku", variant: "outline" },
126
126
  ]}
127
127
  aside={
@@ -183,25 +183,25 @@ routes visitors to the right section quickly.
183
183
  icon: <RocketIcon />,
184
184
  title: "Getting Started",
185
185
  description: "Set up your account and make your first request.",
186
- href: "/docs/getting-started",
186
+ href: "/getting-started",
187
187
  },
188
188
  {
189
189
  icon: <BookOpenIcon />,
190
190
  title: "Guides",
191
191
  description: "Step-by-step tutorials for common use cases.",
192
- href: "/docs",
192
+ href: "/",
193
193
  },
194
194
  {
195
195
  icon: <CodeIcon />,
196
196
  title: "API Reference",
197
197
  description: "Complete reference for every endpoint and type.",
198
- href: "/docs",
198
+ href: "/",
199
199
  },
200
200
  {
201
201
  icon: <WebhookIcon />,
202
202
  title: "Webhooks",
203
203
  description: "Listen to events and build real-time integrations.",
204
- href: "/docs",
204
+ href: "/",
205
205
  },
206
206
  ]}
207
207
  />
@@ -17,7 +17,7 @@ import { Link } from "zudoku/components";
17
17
  ### Basic Internal Link
18
18
 
19
19
  ```tsx
20
- <Link to="/docs/getting-started">Get Started</Link>
20
+ <Link to="/getting-started">Get Started</Link>
21
21
  ```
22
22
 
23
23
  ### Link with State
@@ -39,7 +39,7 @@ import { Link } from "zudoku/components";
39
39
  ### External Link Behavior
40
40
 
41
41
  ```tsx
42
- <Link to="/docs" reloadDocument>
42
+ <Link to="/" reloadDocument>
43
43
  Full Page Reload
44
44
  </Link>
45
45
  ```
@@ -53,7 +53,7 @@ function Navigation() {
53
53
  return (
54
54
  <nav>
55
55
  <Link to="/">Home</Link>
56
- <Link to="/docs">Documentation</Link>
56
+ <Link to="/">Documentation</Link>
57
57
  <Link to="/api">API Reference</Link>
58
58
  <Link to="/blog">Blog</Link>
59
59
  </nav>
@@ -69,7 +69,7 @@ function Breadcrumbs({ path }) {
69
69
  <div className="breadcrumbs">
70
70
  <Link to="/">Home</Link>
71
71
  <span>/</span>
72
- <Link to="/docs">Docs</Link>
72
+ <Link to="/">Docs</Link>
73
73
  <span>/</span>
74
74
  <span>{path}</span>
75
75
  </div>
@@ -134,7 +134,7 @@ function ConditionalLink({ to, disabled, children }) {
134
134
  ### Hash Links
135
135
 
136
136
  ```tsx
137
- <Link to="/docs/api#authentication">Authentication Section</Link>
137
+ <Link to="/api#authentication">Authentication Section</Link>
138
138
  ```
139
139
 
140
140
  ## Advanced Usage