Snapper is an API caching layer built on Fastify and Redis in TypeScript. It makes it easy to snapshot API requests and serve them from an intermediary server to help reduce redundant API calls and navigate externally imposed rate limits.
If a query does not exist in the cache, it will be fetched immediately, cached, and then returned in the same request. If a query has already been cached, the cached value will be returned immediately, regardless of how old it is. If this value is stale (based on the configured TTL), a background process will update its value for future requests, embodying the stale-while-revalidate ideology. This ensures that Snapper balances responsiveness with freshness.
-
Install Redis.
-
Install the server's packages:
npm install
-
Copy .env.example to .env and configure the environment variables.
cp .env.example .env
The available environment variables and their defaults are shown below.
# set server host and port
HOST=0.0.0.0
PORT=3000
# set redis connection URL
REDIS_URL=redis://localhost:6379
# set comma-separated regex CORS origins (optional)
# if empty, all origins are allowed
ALLOWED_ORIGINS=http:\/\/localhost:\d+
# set background job admin dashboard password (viewable at /admin)
ADMIN_DASHBOARD_PASSWORD=admin
# how many background jobs can process at once
CONCURRENCY=50
Add your own queries to the src/server/queries
directory, and make sure to add
them to the src/server/queries/index.ts
file.
Adding a new query is very simple. For a normal URL query, you just need to set
its name, any parameters, URL, and cache TTL. A custom query is similar,
requiring an execute function instead of a URL. You can optionally configure
queries further, such as adding headers or transforming the response body. See
the type in the src/types.ts
file for more details.
type
is the type of the query (URL or Custom).
name
is the name of the query, which will be used in the query route and
also in the cache key.
parameters
are the query parameters that are required by the query. If a
query takes parameters, a separate response will be cached for each unique set
of parameters. You likely want to use these parameters in the URL function.
optionalParameters
are optional query parameters used by the query. If a
query takes parameters, a separate response will be cached for each unique set
of parameters. You likely want to use these parameters in the URL function.
validate
is an optional function that validates the parameters. If it
throws or returns an error, the query will not be fetched and the error will be
returned in the response. If it returns false
, a generic error will be
returned.
ttl
is the cache TTL in seconds. If it's a function (instead of a number),
it will be called with the query's parameters as arguments and the result will
be used.
method
is the optional HTTP method for the request. Defaults to GET
.
url
is the URL for the request. If it's a function (instead of a string),
it will be called with the query's parameters as arguments and the result will
be used.
headers
are the optional headers for the request. If it's a function
(instead of an object), it will be called with the query's parameters as
arguments and the result will be used.
transform
is an optional function that transforms the query's response
body. Its second argument is the query's parameters.
execute
is the function that will be called to execute the query. It will
be called with the query's parameters and a function that lets you get the
result of other queries. This is powerful, as it lets you compose other queries
into new queries.
Start redis server:
redis-server
Run the node server:
npm run serve
### For hot reloading
npm run serve:dev
Run the revalidation processor:
npm run process
Perform a query:
curl -X GET 'http://localhost:3000/q/query_name?parameter=value'
Run the server and revalidation processor via Docker:
npm run start:dev
The server is exposed on port 3030.
View the admin dashboard at http://localhost:3030/admin
Run the server and revalidation processor with pm2 in production (daemon mode):
npm run start:prod
Run the tests:
npm run test