Skip to content

Quickstart: HTTP

This takes you from a new account to a verified cache HIT in front of your own HTTP API, and then shows a purge clearing that entry. Nothing here is throwaway: the service you create and the config you write are the ones you keep. If your origin is a GraphQL API, follow the GraphQL quickstart instead; it adds caching and invalidation from your schema.

Before you start you need an HTTP API that GraphPilot can connect to over the internet, and the ability to change the response headers it sends. It does not have to be public. The examples use GET /products/42 and PUT /products/42; substitute an endpoint from your own API.

Your origin's Cache-Control decides what is stored. A hit never reaches your origin.
  1. Sign up at cockpit.graphpilot.io and create an organization with New organization if you do not belong to one yet; the dialog asks you to accept the Terms of Service. Then install the gpilot CLI and log in:

    Terminal window
    brew install graphpilot/tap/gpilot
    gpilot auth login

    Other platforms: installing the CLI. Several organizations or identities: signing in.

  2. A service is one origin behind GraphPilot, with its own hostname, configuration and cache.

    In the portal, choose New service on your organization’s page. The Create a new service dialog asks for a Service name (Catalog API), an Origin URL (https://api.internal.example.com, the URL of your HTTP API), a Subdomain (catalog-api) and an Environment. See creating a service for what each field accepts. Keep Deploy right away (no schema, default configuration) ticked.

    Select Create service. The next dialog shows the service’s signing key, once. Copy it into your secret manager, then select I have copied the key.

    The service’s dashboard now shows Setting up catalog-api: GraphPilot deploys the service once as a plain pass-through with every setting at its default, then checks for a GraphQL API behind it. For a REST or plain HTTP origin it finds none and says No GraphQL endpoint detected, the service runs as plain HTTP; select Keep as plain HTTP to finish. See set up a new service.

    Then select the service in the CLI:

    Terminal window
    gpilot service select catalog-api

    Once the first deployment is live, your service is reachable at https://catalog-api.k7m2qp.graphpilot.cloud (k7m2qp stands for your organization’s hostname label, which the portal shows). That takes one to two minutes, and for your organization’s first service a few minutes more, up to an hour, while its certificate is issued; the setup shows both. GraphPilot forwards each request to your origin’s host with the path and query string the client sent, so https://catalog-api.k7m2qp.graphpilot.cloud/products/42 reaches /products/42 on your origin. How the origin URL is used (scheme, port, TLS) is on origin.

  3. In the directory you will deploy from, create gpilot.toml. Every setting has a default, so an empty file is valid, and a plain HTTP origin needs nothing else to start:

    gpilot.toml
    # Nothing here is required. See /reference/configuration for every setting.
  4. Send Cache-Control and a surrogate key from your origin

    Section titled “Send Cache-Control and a surrogate key from your origin”

    GraphPilot does not decide on its own that a response may be reused. Your origin says so. Add two headers to the response for GET /products/42:

    HTTP/1.1 200 OK
    Content-Type: application/json
    Cache-Control: s-maxage=60
    Surrogate-Key: product-42 products

    Cache-Control: s-maxage=60 lets GraphPilot keep the response for 60 seconds and share it between callers; see when a response is cached for every directive it reads. Surrogate-Key tags the entry with keys you choose, so you can purge it by name later. GraphPilot removes that header before the response reaches the client. The format is on the Surrogate-Key header.

    Each entry is keyed by the request method and the path, query string included, so /products/42?lang=de is a separate entry. The hostname is not part of the key.

  5. Deploy the config on its own. A plain HTTP service needs no schema. The setup already runs the service on the defaults, so nothing changes in behavior while the file is empty, but from here on the service runs on a configuration you keep in your repository, and the dashboard’s checklist counts this deployment as your own:

    Terminal window
    gpilot deploy

    This picks up ./gpilot.toml, shows what changed since the last deployment, and asks before uploading anything. With no schema.graphql or schema.gql in the directory, it says so before it asks:

    No schema found: deploying as a plain HTTP service, GraphQL features are off.

    That is the expected line for this origin, not an error. It then waits for the deployment to go live, printing each step and any findings the build reported, including a notice that the service has no schema. A failed build never goes live. Flags for CI, other paths and not waiting are in the command reference.

    If the same origin also serves a GraphQL API, deploy it with that schema instead, by following the GraphQL quickstart: requests to its other paths are plain HTTP and get everything on this page.

  6. Send the same request twice to your service hostname:

    Terminal window
    export GRAPHPILOT_HOST=catalog-api.k7m2qp.graphpilot.cloud
    curl -sS -D- -o/dev/null "https://$GRAPHPILOT_HOST/products/42" | grep -i '^gp-'

    The first response is a MISS: it came from your origin and was stored. The second is a HIT:

    gp-cache: HIT
    gp-cache-hits: 1
    gp-cache-age: 4
    gp-cache-max-age: 60
    gp-cache-remaining: 56

    If you see PASS, read the next section.

  7. Clear every response tagged product-42:

    Terminal window
    gpilot purge product-42

    The command shows what it is about to purge and asks you to confirm. Repeat the request from step 6: the first response is a MISS again, and the one after it is a HIT. A purge reaches every edge location. To clear one response without a key of your own, purge its cache key, ck:GET:/products/42, the method and the path without scheme or hostname. See the purge API for every way to purge.

    Your origin can also purge without any call. When the response to a write carries Surrogate-Key, GraphPilot purges the keys it names instead of tagging:

    HTTP/1.1 200 OK
    Surrogate-Key: product-42

    Send that on your origin’s response to PUT /products/42 (or any POST, PUT, PATCH or DELETE) through GraphPilot, and the next GET /products/42 is a MISS. See the Surrogate-Key header.

gp-cache: PASS means the response was not stored, and gp-cache-reason names the rule that refused. These three cause most first-deployment misses:

  • Your origin sets a cookie (CACHE_SKIPPED_SET_COOKIE). A response that sets a session cookie is never stored. Frameworks that touch the session on every request do this by default. See the refusals.
  • The response has no lifetime (CACHE_SKIPPED_NO_CACHE_POLICY or CACHE_SKIPPED_NO_MAX_AGE). Check that your origin’s response carries s-maxage or max-age, and that nothing between your application and GraphPilot replaced the header.
  • The request carried a credential (CACHE_SKIPPED_CREDENTIALED_REQUEST). A request with an Authorization header, a cookie that is not on your cookie allow list, or the header an auth provider reads is only shared when the response says so with public or s-maxage. For answers that differ per caller, see identifying callers and authenticated requests.

Every other reason is in why is nothing cached?, and a second MISS where you expected a HIT in troubleshooting.

Change your clients’ base URL to the service hostname, keeping your paths. Nothing else changes: what reaches your origin is the same request, with a signature added and Accept-Encoding: identity (GraphPilot compresses the response for the client itself).

const response = await fetch("https://catalog-api.k7m2qp.graphpilot.cloud/products/42");
const product = await response.json();

Before you consider this finished, verify the request signature at your origin, so it only trusts traffic that came through GraphPilot, and keep your origin’s clock in sync, because the signature is time-bound. Both are on the go-live checklist.

You want toRead
Understand exactly what gets cached and what does notWhen a response is cached
Tag, partition and purge a whole REST APICaching a REST API
Cache answers that differ per caller or per organizationWho shares an entry
See which features apply to plain HTTPFeatures and limitations
Clear something by hand or from a jobThe purge API
Deploy from a pipelineDeploy from CI
See every settingConfiguration reference
Serve it on your own hostnameCustom domains