An open API service indexing awesome lists of open source software.

https://github.com/karl-horning/graphql-rate-limit-demo

Prototype repo used to test GraphQL rate limiting before production rollout. Demonstrates use of the @rateLimit directive in Apollo Server with a modular ES module setup, custom key generation, and structured schema.
https://github.com/karl-horning/graphql-rate-limit-demo

api apollo-server esmodules graphql graphql-directives graphql-rate-limit graphql-tools learning-graphql nodejs rate-limiting

Last synced: about 2 months ago
JSON representation

Prototype repo used to test GraphQL rate limiting before production rollout. Demonstrates use of the @rateLimit directive in Apollo Server with a modular ES module setup, custom key generation, and structured schema.

Awesome Lists containing this project

README

          

# ๐Ÿšฆ GraphQL Rate Limit Demo

## ๐Ÿ“– Table of Contents

- [๐Ÿšฆ GraphQL Rate Limit Demo](#-graphql-rate-limit-demo)
- [๐Ÿ“– Table of Contents](#-table-of-contents)
- [๐Ÿค“ Overview](#-overview)
- [๐Ÿ“ธ Demo](#-demo)
- [๐Ÿ› ๏ธ Tech Stack](#๏ธ-tech-stack)
- [๐Ÿ“ฆ Installation](#-installation)
- [๐Ÿš€ Scripts](#-scripts)
- [๐Ÿ“ Project Structure](#-project-structure)
- [๐Ÿ“ Code Style](#-code-style)
- [๐Ÿ” Tests](#-tests)
- [๐ŸŒ Live Site](#-live-site)
- [๐Ÿ“Œ To Do](#-to-do)
- [๐Ÿงช Known Issues](#-known-issues)
- [๐Ÿค Contributing](#-contributing)
- [๐Ÿ“„ Licence](#-licence)
- [๐Ÿ™‹ FAQ](#-faq)
- [๐Ÿ‘ค Author](#-author)

---

## ๐Ÿค“ Overview

A lightweight demonstration of how to implement field-level rate limiting in a GraphQL API using `graphql-rate-limit-directive` and Apollo Server. Built with ES modules and a modular file structure.

This GraphQL server applies per-field rate limits using IP address and auth headers. It is ideal for:

- Prototyping request throttling in a Node.js backend.
- Demonstrating use of Apollo Server with custom directives.
- Serving as a base template for future GraphQL projects.

---

## ๐Ÿ“ธ Demo

No live demo currently. Example output on startup:

```bash
Apollo Server started at http://localhost:4000 ๐Ÿš€
```

Example blocked query after exceeding rate limit:

```json
{
"errors": [
{
"message": "Too many requests, please try again in 15 seconds.",
"extensions": {
"code": "RATE_LIMITED"
}
}
]
}
```

---

## ๐Ÿ› ๏ธ Tech Stack

- **GraphQL Server**: Apollo Server
- **Rate Limiting**: graphql-rate-limit-directive
- **Schema Tools**: @graphql-tools/schema
- **Runtime**: Node.js (ESM)
- **Environment Config**: dotenv
- **Console Styling**: chalk

---

## ๐Ÿ“ฆ Installation

```bash
git clone https://github.com/Karl-Horning/graphql-rate-limit-demo.git
cd graphql-rate-limit-demo
npm install
echo "PORT=4000" > .env
```

---

## ๐Ÿš€ Scripts

| Command | Description |
| -------------- | ------------------------------------------ |
| `npm start` | Start the GraphQL server on defined port |
| `npm run test` | Run automated Jest tests for rate limiting |

---

## ๐Ÿ“ Project Structure

```bash
src/
โ”œโ”€โ”€ __tests__/
โ”‚ โ””โ”€โ”€ rateLimit.test.js # Jest tests for rate limiting behaviour
โ”œโ”€โ”€ directives/
โ”‚ โ””โ”€โ”€ rateLimit.js # Directive setup and key generator
โ”œโ”€โ”€ schema/
โ”‚ โ”œโ”€โ”€ index.js # TypeDefs + directive + schema
โ”‚ โ””โ”€โ”€ resolvers.js # Resolvers for queries
โ”œโ”€โ”€ utils/
โ”‚ โ””โ”€โ”€ context.js # Extract IP and auth from request
โ”œโ”€โ”€ server.js # Apollo server config
โ”œโ”€โ”€ index.js # Entry point, loads .env and starts server
```

---

## ๐Ÿ“ Code Style

This project uses:

- ES Modules (`type: "module"` in `package.json`)
- Semantic console logging with `chalk`
- `.env` for configuration
- Modular file organisation by concern

---

## ๐Ÿ” Tests

Automated tests are written using **Jest** and cover basic rate limiting behaviour.

The tests simulate multiple GraphQL queries and check that:

- The first request is **allowed**.
- The second request is **rate limited** and returns the expected error message.

To run the tests:

```bash
npm run test
```

Example output:

```bash
PASS src/__tests__/rateLimit.test.js
Rate limiting
โœ“ should allow the first request (xx ms)
โœ“ should rate limit the second request (xx ms)
```

---

## ๐ŸŒ Live Site

*Not currently deployed โ€” run locally using the instructions above.*

---

## ๐Ÿ“Œ To Do

- [x] Modularise monolithic GraphQL setup
- [x] Switch to ES modules
- [x] Add example rate limit tests (for example, with `curl`, Postman, or automated)
- [ ] Add optional Redis integration for distributed rate limiting
- [ ] Add logging middleware for introspection

---

## ๐Ÿงช Known Issues

- IP detection via `req.connection.remoteAddress` may be unreliable behind proxies (consider `X-Forwarded-For` in production)
- Rate limiting applies uniformly to all clients by IP and auth; per-user JWT support is not yet implemented

---

## ๐Ÿค Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you'd like to change.

---

## ๐Ÿ“„ Licence

MIT ยฉ 2025 Karl Horning

---

## ๐Ÿ™‹ FAQ

**Q: Why am I seeing a "PORT variable not provided" error during startup?**
A: Ensure your `.env` file contains a `PORT=4000` or similar line.

**Q: How can I customise rate limits per field?**
A: Use the `@rateLimit(limit: X, duration: Y)` directive on specific fields in the schema.

**Q: Why are my queries getting blocked?**
A: You're likely exceeding the `@rateLimit` values based on your IP and auth header.

**Q: Can I disable rate limiting on some fields?**
A: Yes, simply omit the `@rateLimit` directive on that field.

---

## ๐Ÿ‘ค Author

Made with โค๏ธ by [Karl Horning](https://github.com/Karl-Horning)