-
Notifications
You must be signed in to change notification settings - Fork 16
Add urql integration package #671
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
jeffkreeftmeijer
wants to merge
1
commit into
main
Choose a base branch
from
add-urql-integration
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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,115 @@ | ||
| # `@appsignal/urql` | ||
|
|
||
| - [AppSignal.com website][appsignal] | ||
| - [Documentation][docs] | ||
| - [Support][contact] | ||
|
|
||
| The `@appsignal/javascript` integration for urql GraphQL client. | ||
|
|
||
| See also the [mono repo README](../../README.md) for more information. | ||
|
|
||
| ## Installation | ||
|
|
||
| Add the `@appsignal/urql` and `@appsignal/javascript` packages to your `package.json`. Then, run `yarn install`/`npm install`. | ||
|
|
||
| You can also add these packages to your `package.json` on the command line: | ||
|
|
||
| ``` | ||
| yarn add @appsignal/javascript @appsignal/urql urql wonka | ||
| npm install --save @appsignal/javascript @appsignal/urql urql wonka | ||
| ``` | ||
|
|
||
| ## Usage | ||
|
|
||
| ### Urql Exchange | ||
|
|
||
| The `@appsignal/urql` package provides a custom urql exchange that automatically reports GraphQL errors to AppSignal. This exchange intercepts all query and mutation results and reports any errors without requiring changes to individual `useQuery` calls. | ||
|
|
||
| ```typescript | ||
| import { createClient, fetchExchange } from 'urql'; | ||
| import Appsignal from '@appsignal/javascript'; | ||
| import { createAppsignalExchange } from '@appsignal/urql'; | ||
|
|
||
| const appsignal = new Appsignal({ | ||
| key: 'YOUR FRONTEND API KEY' | ||
| }); | ||
|
|
||
| const client = createClient({ | ||
| url: 'https://api.example.com/graphql', | ||
| exchanges: [createAppsignalExchange(appsignal), fetchExchange] | ||
| }); | ||
| ``` | ||
|
|
||
| The exchange will automatically: | ||
| - Report all GraphQL errors to AppSignal | ||
| - Include the GraphQL query body as a parameter (visible in AppSignal's error details) | ||
| - Include the endpoint URL as a tag | ||
| - Include operation name and type as tags (when available) | ||
|
|
||
| ### Error Details | ||
|
|
||
| When a GraphQL error occurs, AppSignal will receive: | ||
|
|
||
| - **Error message**: A concatenation of all GraphQL error messages | ||
| - **Tags**: | ||
| - `endpoint`: The GraphQL endpoint URL | ||
| - `operationName`: The name of the GraphQL operation (if specified) | ||
| - `operationType`: The type of operation (query, mutation, subscription) | ||
| - **Parameters**: | ||
| - `query`: The full GraphQL query body | ||
|
|
||
| This provides complete context for debugging GraphQL errors in your application. | ||
|
|
||
| ## Development | ||
|
|
||
| ### Installation | ||
|
|
||
| Make sure mono is installed and bootstrapped, see the [project README's development section](../../README.md#dev-install) for more information. | ||
|
|
||
| You can then run the following to start the compiler in _watch_ mode. This automatically compiles both the ES Module and CommonJS variants: | ||
|
|
||
| ```bash | ||
| yarn build:watch | ||
| ``` | ||
|
|
||
| You can also build the library without watching the directory: | ||
|
|
||
| ``` | ||
| yarn build # build both CJS and ESM | ||
| yarn build:cjs # just CJS | ||
| yarn build:esm # just ESM | ||
| ``` | ||
|
|
||
| ### Testing | ||
|
|
||
| The tests for this library use [Jest](https://jestjs.io) as the test runner. Once you've installed the dependencies, you can run the following command in the root of this repository to run the tests for all packages, or in the directory of a package to run only the tests pertaining to that package: | ||
|
|
||
| ```bash | ||
| yarn test | ||
| ``` | ||
|
|
||
| ### Versioning | ||
|
|
||
| This repo uses [Semantic Versioning][semver] (often referred to as _semver_). Each package in the repository is versioned independently from one another. | ||
|
|
||
| ## Contributing | ||
|
|
||
| Thinking of contributing to this repo? Awesome! 🚀 | ||
|
|
||
| Please follow our [Contributing guide][contributing-guide] in our documentation and follow our [Code of Conduct][coc]. | ||
|
|
||
| Also, we would be very happy to send you Stroopwafles. Have look at everyone we send a package to so far on our [Stroopwafles page][waffles-page]. | ||
|
|
||
| ## Support | ||
|
|
||
| [Contact us][contact] and speak directly with the engineers working on AppSignal. They will help you get set up, tweak your code and make sure you get the most out of using AppSignal. | ||
|
|
||
| [appsignal]: https://appsignal.com | ||
| [appsignal-sign-up]: https://appsignal.com/users/sign_up | ||
| [contact]: mailto:support@appsignal.com | ||
| [coc]: https://docs.appsignal.com/appsignal/code-of-conduct.html | ||
| [waffles-page]: https://appsignal.com/waffles | ||
| [docs]: http://docs.appsignal.com | ||
| [contributing-guide]: http://docs.appsignal.com/appsignal/contributing.html | ||
|
|
||
| [semver]: http://semver.org/ |
This file contains hidden or 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,8 @@ | ||
| module.exports = { | ||
| preset: "ts-jest", | ||
| testEnvironment: "jsdom", | ||
| roots: ["<rootDir>/src"], | ||
| transform: { | ||
| "^.+\\.tsx?$": "ts-jest" | ||
| } | ||
| } |
This file contains hidden or 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,34 @@ | ||
| { | ||
| "name": "@appsignal/urql", | ||
| "version": "1.0.0", | ||
| "main": "dist/cjs/index.js", | ||
| "module": "dist/esm/index.js", | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "https://github.com/appsignal/appsignal-javascript.git", | ||
| "directory": "packages/urql" | ||
| }, | ||
| "license": "MIT", | ||
| "scripts": { | ||
| "build": "npm run build:cjs && npm run build:esm", | ||
| "build:esm": "tsc -p tsconfig.esm.json", | ||
| "build:esm:watch": "tsc -p tsconfig.esm.json -w --preserveWatchOutput", | ||
| "build:cjs": "tsc -p tsconfig.cjs.json", | ||
| "build:cjs:watch": "tsc -p tsconfig.cjs.json -w --preserveWatchOutput", | ||
| "build:watch": "run-p build:cjs:watch build:esm:watch", | ||
| "clean": "rimraf dist coverage", | ||
| "link:npm": "npm link", | ||
| "test": "jest --passWithNoTests", | ||
| "test:watch": "jest --watch" | ||
| }, | ||
| "dependencies": { | ||
| "@appsignal/javascript": "=1.6.1" | ||
| }, | ||
| "peerDependencies": { | ||
| "urql": ">= 2.0.0 < 5", | ||
| "wonka": ">= 4.0.0 < 7" | ||
| }, | ||
| "publishConfig": { | ||
| "access": "public" | ||
| } | ||
| } |
This file contains hidden or 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,68 @@ | ||
| import { pipe, tap } from 'wonka'; | ||
| import type Appsignal from '@appsignal/javascript'; | ||
|
|
||
| /** | ||
| * Custom urql exchange that automatically reports GraphQL errors to AppSignal. | ||
| * | ||
| * This exchange intercepts all query/mutation results and reports any errors | ||
| * to AppSignal without requiring changes to individual useQuery calls. | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * import { createClient, fetchExchange } from 'urql'; | ||
| * import Appsignal from '@appsignal/javascript'; | ||
| * import { createAppsignalExchange } from '@appsignal/urql'; | ||
| * | ||
| * const appsignal = new Appsignal({ | ||
| * key: 'YOUR FRONTEND API KEY' | ||
| * }); | ||
| * | ||
| * const client = createClient({ | ||
| * url: 'https://api.example.com/graphql', | ||
| * exchanges: [createAppsignalExchange(appsignal), fetchExchange] | ||
| * }); | ||
| * ``` | ||
| */ | ||
| export const createAppsignalExchange = (appsignal: Appsignal) => ({ forward, client }: any) => (ops$: any) => { | ||
| return pipe( | ||
| forward(ops$), | ||
| tap((result: any) => { | ||
| if (result.error) { | ||
| const { error, operation } = result; | ||
|
|
||
| // Convert CombinedError to a proper Error with meaningful message | ||
| const errorMessage = error.graphQLErrors?.length > 0 | ||
| ? error.graphQLErrors.map((e: any) => e.message).join(', ') | ||
| : error.message; | ||
|
|
||
| const reportError = new Error(`GraphQL Error: ${errorMessage}`); | ||
| reportError.name = 'GraphQLError'; | ||
| (reportError as any).stack = error.stack || reportError.stack; | ||
|
|
||
| // Send error to AppSignal with metadata | ||
| appsignal.sendError(reportError, (span) => { | ||
| // Add endpoint URL as a tag | ||
| if (client?.url) { | ||
| span.setTags({ endpoint: client.url }); | ||
| } | ||
|
|
||
| // Add GraphQL query body as a param | ||
| if (operation?.query) { | ||
| const queryBody = operation.query.loc?.source?.body; | ||
| if (queryBody) { | ||
| span.setParams({ query: queryBody }); | ||
| } | ||
| } | ||
|
|
||
| // Add operation metadata | ||
| if (operation?.operationName) { | ||
| span.setTags({ operationName: operation.operationName }); | ||
| } | ||
| if (operation?.kind) { | ||
| span.setTags({ operationType: operation.kind }); | ||
| } | ||
| }); | ||
| } | ||
| }) | ||
| ); | ||
| }; |
This file contains hidden or 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,7 @@ | ||
| { | ||
| "extends": "./tsconfig.json", | ||
| "compilerOptions": { | ||
| "outDir": "./dist/cjs", | ||
| "module": "commonjs" | ||
| } | ||
| } |
This file contains hidden or 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,7 @@ | ||
| { | ||
| "extends": "./tsconfig.json", | ||
| "compilerOptions": { | ||
| "outDir": "./dist/esm", | ||
| "module": "es6" | ||
| } | ||
| } |
This file contains hidden or 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,12 @@ | ||
| { | ||
| "extends": "../../tsconfig.json", | ||
| "include": ["src/**/*"], | ||
| "exclude": [ | ||
| "src/**/__tests__", | ||
| "src/**/__mocks__" | ||
| ], | ||
| "compilerOptions": { | ||
| "rootDir": "./src", | ||
| "target": "es5" | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should add tests for this as well.