-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(graphql): add graphql package (#708)
- Loading branch information
1 parent
1890503
commit 12e916c
Showing
19 changed files
with
682 additions
and
2 deletions.
There are no files selected for viewing
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
module.exports = { | ||
root: true, | ||
extends: ["custom"], | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
**/*.log* | ||
/coverage | ||
/dist | ||
/node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
# @dzangolab/fastify-graphql | ||
|
||
A [Fastify](https://github.com/fastify/fastify) plugin that provides an easy integration of mercurius graphql server in a fastify API. | ||
|
||
The plugin is a thin wrapper around the [mercurius](https://mercurius.dev/#/) plugin. | ||
|
||
## Requirements | ||
|
||
* @dzangolab/fastify-config | ||
* @dzangolab/fastify-slonik | ||
* graphql | ||
* [mercurius](https://mercurius.dev/#/) | ||
* mercurius-codegen | ||
* slonik | ||
|
||
## Installation | ||
|
||
In a simple repo: | ||
|
||
```bash | ||
npm install @dzangolab/fastify-graphql graphql mercurius mercurius-codegen | ||
``` | ||
|
||
If using in a monorepo with pnpm: | ||
|
||
```bash | ||
pnpm add --filter "myrepo" @dzangolab/fastify-graphql graphql mercurius mercurius-codegen | ||
``` | ||
|
||
## Usage | ||
|
||
Add a `graphql` block to your config: | ||
|
||
```javascript | ||
import { parse } from "@dzangolab/fastify-config"; | ||
import dotenv from "dotenv"; | ||
|
||
import { resolvers, schema } from "path/to/graphql"; | ||
|
||
import type { ApiConfig } from "@dzangolab/fastify-config"; | ||
|
||
dotenv.config(); | ||
|
||
const config: ApiConfig = { | ||
... | ||
graphql: { | ||
enabled: parse(process.env.GRAPHQL_ENABLED, true) as boolean, | ||
graphiql: parse(process.env.GRAPHIQL_ENABLED, false) as boolean, | ||
path: parse(process.env.GRAPHQL_PATH, "/graphql") as string, | ||
resolvers, | ||
schema, | ||
}, | ||
... | ||
}; | ||
|
||
export default config; | ||
``` | ||
|
||
Register the plugin with your Fastify instance: | ||
|
||
```javascript | ||
import configPlugin from "@dzangolab/fastify-config"; | ||
import graphqlPlugin from "@dzangolab/fastify-graphql"; | ||
import fastify from "fastify"; | ||
|
||
import config from "./config"; | ||
|
||
import type { ApiConfig } from "@dzangolab/fastify-config"; | ||
import type { FastifyInstance } from "fastify"; | ||
|
||
// Create fastify instance | ||
const fastify = Fastify({ | ||
logger: config.logger, | ||
}); | ||
|
||
// Register fastify-config plugin | ||
fastify.register(configPlugin, { config }); | ||
|
||
// Register fastify-graphql plugin | ||
fastify.register(graphqlPlugin); | ||
|
||
await fastify.listen({ | ||
port: config.port, | ||
host: "0.0.0.0", | ||
}); | ||
``` | ||
|
||
## Configuration | ||
|
||
The `graphql` block in the `ApiConfig` supports all of the [original mercurius plugin's options](https://mercurius.dev/#/docs/api/options?id=plugin-options). | ||
|
||
An additional `enabled` (boolean) option allows you to disable the graphql server. | ||
|
||
## Context | ||
|
||
The fastify-graphql plugin will generate a graphql context on every request that will include the following attributes: | ||
|
||
| Attribute | Type | Description | | ||
|------------|------|-------------| | ||
| `config` | `ApiConfig` | The fastify servers' config (as per @dzangolab/fastify-config) | | ||
| `database` | `Database` | The fastify server's slonik instance (as per @dzangolab/fastify-slonik) | | ||
| `sql` | `SqlTaggedTemplate` | The fastify server's `sql` tagged template from slonik | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
{ | ||
"name": "@dzangolab/fastify-graphql", | ||
"version": "0.69.0", | ||
"description": "Fastify graphql plugin", | ||
"homepage": "https://github.com/dzangolab/fastify/tree/main/packages/graphql#readme", | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/dzangolab/fastify.git", | ||
"directory": "packages/graphql" | ||
}, | ||
"license": "MIT", | ||
"type": "module", | ||
"exports": { | ||
".": { | ||
"import": "./dist/dzangolab-fastify-graphql.js", | ||
"require": "./dist/dzangolab-fastify-graphql.umd.cjs" | ||
} | ||
}, | ||
"main": "./dist/dzangolab-fastify-graphql.umd.cjs", | ||
"module": "./dist/dzangolab-fastify-graphql.js", | ||
"types": "./dist/types/index.d.ts", | ||
"files": [ | ||
"dist" | ||
], | ||
"scripts": { | ||
"build": "vite build && tsc --emitDeclarationOnly && mv dist/src dist/types", | ||
"lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --ignore-path .gitignore", | ||
"lint:fix": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore", | ||
"sort-package": "npx sort-package-json", | ||
"test": "vitest run --coverage", | ||
"typecheck": "tsc --noEmit -p tsconfig.json --composite false" | ||
}, | ||
"dependencies": { | ||
"graphql-tag": "2.12.6", | ||
"@graphql-tools/merge": "9.0.4" | ||
}, | ||
"devDependencies": { | ||
"@dzangolab/fastify-config": "0.69.0", | ||
"@dzangolab/fastify-slonik": "0.69.0", | ||
"@types/node": "20.12.2", | ||
"@typescript-eslint/eslint-plugin": "5.62.0", | ||
"@typescript-eslint/parser": "5.62.0", | ||
"@vitest/coverage-istanbul": "2.0.4", | ||
"eslint": "8.56.0", | ||
"eslint-config-custom": "0.69.0", | ||
"fastify": "4.10.2", | ||
"fastify-plugin": "4.4.0", | ||
"graphql": "16.9.0", | ||
"mercurius": "14.1.0", | ||
"prettier": "2.8.8", | ||
"slonik": "38.0.0", | ||
"tsconfig": "0.69.0", | ||
"typescript": "4.9.5", | ||
"vite": "4.5.3", | ||
"vitest": "2.0.4", | ||
"zod": "3.23.8" | ||
}, | ||
"peerDependencies": { | ||
"@dzangolab/fastify-config": "0.69.0", | ||
"@dzangolab/fastify-slonik": "0.69.0", | ||
"fastify": ">=4.9.2", | ||
"fastify-plugin": ">=4.3.0", | ||
"graphql": ">=16.9.0", | ||
"mercurius": ">=14.1.0", | ||
"slonik": ">=38.0.0", | ||
"zod": ">=3.23.8" | ||
}, | ||
"engines": { | ||
"node": ">=16", | ||
"pnpm": ">=8" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
import fastify from "fastify"; | ||
import { describe, expect, it, beforeEach } from "vitest"; | ||
|
||
import createConfig from "./helpers/createConfig"; | ||
import testPlugin from "./helpers/testPlugin"; | ||
import testPluginAsync from "./helpers/testPluginAsync"; | ||
import graphqlPlugin from "../plugin"; | ||
|
||
import type { FastifyInstance } from "fastify"; | ||
|
||
describe("Graphql Context", async () => { | ||
let api: FastifyInstance; | ||
|
||
beforeEach(async () => { | ||
api = await fastify(); | ||
}); | ||
|
||
it("Should add context property and value from callback test plugin", async () => { | ||
api.addHook("onRequest", async (request) => { | ||
request.config = createConfig([testPlugin]); | ||
}); | ||
|
||
api.decorate("config", createConfig([testPlugin])); | ||
|
||
api.register(testPlugin); | ||
|
||
await api.register(graphqlPlugin); | ||
|
||
const response = await api.inject({ | ||
method: "POST", | ||
payload: { | ||
operationName: "test", | ||
query: ` | ||
query test { | ||
test{ | ||
propertyTwo | ||
propertyOne | ||
} | ||
} | ||
`, | ||
}, | ||
url: "/graphql", | ||
}); | ||
|
||
expect(JSON.parse(response.payload).data.test).toEqual({ | ||
//eslint-disable-next-line unicorn/no-null | ||
propertyOne: null, | ||
propertyTwo: "Property Two", | ||
}); | ||
|
||
expect(api).toHaveProperty(["propertyTwo"], "Property Two"); | ||
}); | ||
|
||
it("Should add context property and value from Async test plugin", async () => { | ||
api.addHook("onRequest", async (request) => { | ||
request.config = createConfig([testPluginAsync]); | ||
}); | ||
|
||
api.decorate("config", createConfig([testPluginAsync])); | ||
|
||
await api.register(testPluginAsync); | ||
|
||
await api.register(graphqlPlugin); | ||
|
||
const response = await api.inject({ | ||
method: "POST", | ||
payload: { | ||
operationName: "test", | ||
query: ` | ||
query test { | ||
test{ | ||
propertyTwo | ||
propertyOne | ||
} | ||
} | ||
`, | ||
}, | ||
url: "/graphql", | ||
}); | ||
|
||
expect(JSON.parse(response.payload).data.test).toEqual({ | ||
//eslint-disable-next-line unicorn/no-null | ||
propertyTwo: null, | ||
propertyOne: "Property One", | ||
}); | ||
|
||
expect(api).toHaveProperty(["propertyOne"], "Property One"); | ||
}); | ||
|
||
it("Should add context property and value from Async/Callback test plugin", async () => { | ||
api.addHook("onRequest", async (request) => { | ||
request.config = createConfig([testPlugin, testPluginAsync]); | ||
}); | ||
|
||
api.decorate("config", createConfig([testPlugin, testPluginAsync])); | ||
|
||
await api.register(graphqlPlugin); | ||
await api.register(testPlugin); | ||
await api.register(testPluginAsync); | ||
|
||
const response = await api.inject({ | ||
method: "POST", | ||
payload: { | ||
operationName: "test", | ||
query: ` | ||
query test { | ||
test{ | ||
propertyTwo | ||
propertyOne | ||
} | ||
} | ||
`, | ||
}, | ||
url: "/graphql", | ||
}); | ||
|
||
expect(JSON.parse(response.payload).data.test).toEqual({ | ||
propertyTwo: "Property Two", | ||
propertyOne: "Property One", | ||
}); | ||
|
||
expect(api).toHaveProperty(["propertyTwo"], "Property Two"); | ||
|
||
expect(api).toHaveProperty(["propertyOne"], "Property One"); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/* istanbul ignore file */ | ||
import type { MercuriusEnabledPlugin } from "../../types"; | ||
import type { ApiConfig } from "@dzangolab/fastify-config"; | ||
import type { MercuriusContext } from "mercurius"; | ||
|
||
const schema = ` | ||
type Query { | ||
test: Response | ||
} | ||
type Response { | ||
propertyOne: String | ||
propertyTwo: String | ||
} | ||
`; | ||
|
||
const resolvers = { | ||
Query: { | ||
test: async (_: unknown, __: unknown, context: MercuriusContext) => ({ | ||
propertyOne: context.propertyOne, | ||
propertyTwo: context.propertyTwo, | ||
}), | ||
}, | ||
}; | ||
|
||
const createConfig = (plugins: MercuriusEnabledPlugin[]) => { | ||
const config: ApiConfig = { | ||
appName: "app", | ||
appOrigin: ["http://localhost"], | ||
baseUrl: "http://localhost", | ||
env: "development", | ||
logger: { | ||
level: "debug", | ||
}, | ||
name: "Test", | ||
port: 3000, | ||
protocol: "http", | ||
rest: { | ||
enabled: true, | ||
}, | ||
version: "0.1", | ||
graphql: { | ||
enabled: true, | ||
graphiql: false, | ||
path: "/graphql", | ||
schema, | ||
resolvers, | ||
plugins, | ||
}, | ||
slonik: { | ||
db: { | ||
databaseName: "test", | ||
host: "localhost", | ||
password: "password", | ||
username: "username", | ||
}, | ||
}, | ||
}; | ||
|
||
return config; | ||
}; | ||
|
||
export default createConfig; |
Oops, something went wrong.