Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/improve-readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@labdigital/graphql-codegen-bruno": patch
"@labdigital/graphql-codegen-k6": patch
"@labdigital/graphql-codegen-typedefs": patch
---

Improve README
1 change: 0 additions & 1 deletion .nvmrc

This file was deleted.

86 changes: 86 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# GraphQL Codegen Plugins

Plugins for [GraphQL Code Generator](https://the-guild.dev/graphql/codegen),
maintained by [Lab Digital](https://www.labdigital.nl).

## Packages

| Package | Version | Description |
| ------- | ------- | ----------- |
| [`@labdigital/graphql-codegen-bruno`](./packages/bruno/README.md) | [![npm](https://img.shields.io/npm/v/@labdigital/graphql-codegen-bruno)](https://www.npmjs.com/package/@labdigital/graphql-codegen-bruno) | Generates a [Bruno](https://www.usebruno.com) request (`.bru` file) for every GraphQL operation in your codebase. |
| [`@labdigital/graphql-codegen-k6`](./packages/k6/README.md) | [![npm](https://img.shields.io/npm/v/@labdigital/graphql-codegen-k6)](https://www.npmjs.com/package/@labdigital/graphql-codegen-k6) | Generates a typed SDK for your GraphQL operations that you can use in [k6](https://k6.io) load tests. |
| [`@labdigital/graphql-codegen-typedefs`](./packages/typedefs/README.md) | [![npm](https://img.shields.io/npm/v/@labdigital/graphql-codegen-typedefs)](https://www.npmjs.com/package/@labdigital/graphql-codegen-typedefs) | Generates a TypeScript module that exports your GraphQL schema as a `typeDefs` document. |

## Requirements

- Node.js 22 or newer
- `graphql` `^16.0.0 || ^17.0.0`
- `@graphql-codegen/cli` 7.x

All packages are published as ES modules only.

## Usage

Install the CLI and the plugin you need, then reference the plugin by its
package name in your `codegen.ts`:

```sh
pnpm add -D @graphql-codegen/cli graphql @labdigital/graphql-codegen-typedefs
```

```ts
import type { CodegenConfig } from "@graphql-codegen/cli";

const config: CodegenConfig = {
schema: "schema.graphql",
generates: {
"src/generated/typedefs.ts": {
plugins: ["@labdigital/graphql-codegen-typedefs"],
},
},
};

export default config;
```

```sh
pnpm graphql-codegen --config codegen.ts
```

See the README of each package for its configuration options and example
output.

## Development

This is a [pnpm](https://pnpm.io) workspace (pnpm 12, see `packageManager` in
`package.json`) using [Turborepo](https://turborepo.com) for builds,
[tsdown](https://tsdown.dev) for bundling, [Vitest](https://vitest.dev) for
tests and [Biome](https://biomejs.dev) for formatting and linting.

```sh
pnpm install # install dependencies
pnpm build # build all packages (packages/*/dist)
pnpm test # run the tests
pnpm check # biome ci + typecheck, as run in CI
pnpm format # apply biome formatting and safe fixes
```

## Releasing

Releases are managed with [Changesets](https://github.com/changesets/changesets).

1. Add a changeset to every pull request that changes a published package:

```sh
pnpm changeset
```

2. When the pull request is merged into `main`, the release workflow opens (or
updates) a "Release new version" pull request that bumps the versions and
updates the changelogs.
3. Merging that pull request publishes the new versions to npm (with
provenance, via npm trusted publishing).

## License

[MIT](./LICENSE) © Lab Digital
205 changes: 177 additions & 28 deletions packages/bruno/README.md
Original file line number Diff line number Diff line change
@@ -1,57 +1,206 @@
## GraphQL Codegen Bruno Plugin
# @labdigital/graphql-codegen-bruno

[![npm](https://img.shields.io/npm/v/@labdigital/graphql-codegen-bruno)](https://www.npmjs.com/package/@labdigital/graphql-codegen-bruno)

This plugin generates a directory with
[Bruno](https://github.com/usebruno/bruno) files with all GraphQL queries in
your codebase
A [GraphQL Code Generator](https://the-guild.dev/graphql/codegen) plugin that
generates a [Bruno](https://www.usebruno.com) request (`.bru` file) for every
named GraphQL operation in your codebase.

Use it to keep an API collection in sync with the queries and mutations your
application actually sends: every request contains the operation, the
fragments it uses and example variables derived from the schema, so you can
run it from Bruno right away.

## Installation

# Installation
```sh
pnpm add -d @labdigital/graphql-codegen-bruno
pnpm add -D @labdigital/graphql-codegen-bruno @graphql-codegen/cli graphql
```

# Usage
Create a `codegen.ts` file in the root of your project with the following content:
## Usage

Add an output to your `codegen.ts`. The plugin writes the `.bru` files to the
**directory** of the output file; the output file itself gets a JSON index of
the generated requests.

```ts
import type { CodegenConfig } from "@graphql-codegen/cli";

const config: CodegenConfig = {
schema:
"schema.graphql",
documents: [
"src/**/*.{ts,tsx}"
],
schema: "schema.graphql",
documents: ["src/**/*.graphql"],
generates: {
// Generate Bruno files in the api-collection directory
"api-collection/generated.json": {
// The .bru files are written to the directory of this output file.
// The file itself contains an index of the generated requests.
"api-collection/generated/index.json": {
plugins: ["@labdigital/graphql-codegen-bruno"],
config: {

// Clean the output directory before generating the files
clean: true

// Set default values for the generated Bruno variables
// Empty the output directory before generating
clean: true,
// Headers added to every request
headers: {
Authorization: "Bearer {{token}}",
},
// Override the generated example value of top-level variables
defaults: {
locale: "nl-NL",
currency: "EUR"
}
},
},
},
},
};

export default config;
```

Then run the following command:
Then run:

```sh
pnpx graphql-codegen --config codegen.ts
pnpm graphql-codegen --config codegen.ts
```

This results in:

```text
api-collection/
├── bruno.json # your Bruno collection (not generated)
└── generated/
├── index.json
├── mutations/
│ └── AddToCart.bru
└── queries/
├── GetProduct.bru
└── ListProducts.bru
```

The requests are sent to `{{graphql-gateway}}/graphql`, so define a
`graphql-gateway` variable (for example `http://localhost:4000`) in your Bruno
environment.

## Configuration

| Option | Type | Default | Description |
| ------ | ---- | ------- | ----------- |
| `clean` | `boolean` | `false` | Remove everything in the output directory (the directory of the output file) before generating. |
| `headers` | `Record<string, string>` | `{}` | Headers added to the `headers` block of every request. Values may use Bruno variables, such as `{{token}}`. |
| `defaults` | `Record<string, unknown>` | `{}` | Values for operation variables, by variable name. A default replaces the generated example value of a top-level variable with the same name; variables that the operation does not declare are ignored. |

## Example output

Given this schema and operation (with the `ProductFields` fragment defined in
another file):

```graphql
type Query {
product(id: ID!, locale: String): Product
}

type Product {
id: ID!
name: String!
price: Float!
}
```

# Notes
The `api-collection/generated.json` seems to be needed for GraphQL codegen
to work (we need to generate a file, not a directory). If you know a way to
generate a directory instead of a file, please us know
```graphql
query GetProduct($id: ID!, $locale: String) {
product(id: $id, locale: $locale) {
...ProductFields
}
}
```

the configuration above generates `queries/GetProduct.bru`:

```text
meta {
name: GetProduct
type: graphql
}

post {
url: {{graphql-gateway}}/graphql
body: graphql
auth: none
}

headers {
Authorization: Bearer {{token}}
}

body:graphql {
query GetProduct($id: ID!, $locale: String) {
product(id: $id, locale: $locale) {
...ProductFields
}
}
fragment ProductFields on Product {
id
name
price
}

}

body:graphql:vars {
{
"id": "example-id",
"locale": "nl-NL"
}
}
```

and `index.json`, which maps each operation to its file and source:

```json
{
"AddToCart": {
"filename": "AddToCart.bru",
"source": "../../src/graphql/add-to-cart.graphql"
},
"GetProduct": {
"filename": "GetProduct.bru",
"source": "../../src/graphql/get-product.graphql"
},
"ListProducts": {
"filename": "ListProducts.bru",
"source": "../../src/graphql/list-products.graphql"
}
}
```

### Example variables

Variables get an example value based on their type:

| Type | Example value |
| ---- | ------------- |
| `Int` | `123` |
| `Float` | `123.45` |
| `String` | `"example"` |
| `Boolean` | `true` |
| `ID` | `"example-id"` |
| Custom scalar | `"example"` |
| Enum | The first enum value |
| Input object | An object with an example value for every field |
| List | A list with one example value |

## Notes and limitations

- Codegen requires a file as output, so the plugin needs an output *file* even
though it generates a directory. The file is used for the JSON index.
- `clean: true` removes **everything** in the directory of the output file.
Point the output to a dedicated directory inside your collection, not to the
collection root, or it removes your `bruno.json` and environments as well.
- Queries are written to `queries/`; mutations (and subscriptions) to
`mutations/`. Files are named after the operation, so operation names must be
unique.
- Unnamed operations are skipped.
- The request body contains the complete source document of the operation
(one `.graphql` file, or one `gql` template literal in TypeScript), followed
by the fragments the operation uses. Put one operation per document;
otherwise every request contains all operations of that document, and
fragments defined in the same document are included twice.
- The URL (`{{graphql-gateway}}/graphql`) and `auth: none` are fixed.
- `defaults` only applies to top-level variables; it replaces the whole value,
it does not merge into input objects.
Loading
Loading