Skip to content
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

create separate package for @graphql-helix/core #140

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 8 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
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
run: yarn install --frozen-lockfile --ignore-engines --update-checksums
- run: yarn build
- run: yarn lint
- run: yarn workspace graphql-helix test
- run: yarn workspace @graphql-helix/core test
env:
CI: true
- run: yarn workspace graphql-helix esm:test
- run: yarn workspace @graphql-helix/core esm:test
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"workspaces": [
"packages/core",
"packages/graphiql",
"packages/graphql-helix",
"examples/*",
"website"
],
Expand Down
1 change: 0 additions & 1 deletion packages/core/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
lib/render-graphiql.ts
deno_dist
1 change: 0 additions & 1 deletion packages/core/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
export * from "./get-graphql-parameters";
export * from "./process-request";
export * from "./render-graphiql";
export * from "./should-render-graphiql";
export * from "./types";
export * from "./errors";
Expand Down
51 changes: 0 additions & 51 deletions packages/core/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,57 +15,6 @@ export interface GraphQLParams {
variables?: string | { [name: string]: any };
}

export type HybridSubscriptionTransportConfig = {
/* Enable SSE transport as an option */
sse?: string;
/* Enable Legacy graphql-ws protocol transport as an option. */
legacyWS?: string;
/* Enable graphql-transport-ws protocol transport as an option */
transportWS?: string;
};

export interface RenderGraphiQLOptions {
/**
* An optional GraphQL string to use when no query is provided and no stored
* query exists from a previous session. If undefined is provided, GraphiQL
* will use its own default query.
*/
defaultQuery?: string;
/**
* Whether to open the variable editor by default. Defaults to `true`.
*/
defaultVariableEditorOpen?: boolean;
/**
* The endpoint requests should be sent. Defaults to `"/graphql"`.
*/
endpoint?: string;
/**
* The initial headers to render inside the header editor. Defaults to `"{}"`.
*/
headers?: string;
/**
* Whether the header editor is enabled. Defaults to `true`.
*/
headerEditorEnabled?: boolean;
/**
* A cryptographic nonce for use with Content-Security-Policy.
*/
nonce?: string;
/**
* The endpoint subscription requests should be sent to. Defaults to the value of the `endpoint` parameter.
*/
subscriptionsEndpoint?: string;
/**
* Use legacy web socket protocol `graphql-ws` instead of the more current standard `graphql-transport-ws`
*/
useWebSocketLegacyProtocol?: boolean;
hybridSubscriptionTransportConfig?: HybridSubscriptionTransportConfig;
/**
* Persist headers in local storage.
*/
shouldPersistHeaders?: boolean;
}

export interface ProcessRequestOptions<TContext, TRootValue> {
/**
* A function whose return value is passed in as the `context` to `execute`.
Expand Down
7 changes: 3 additions & 4 deletions packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "graphql-helix",
"name": "@graphql-helix/core",
"version": "1.10.3",
"description": "A highly evolved GraphQL HTTP Server 🧬",
"keywords": [
Expand Down Expand Up @@ -29,10 +29,9 @@
"dist-esm"
],
"scripts": {
"build": "yarn build-render-graphiql && yarn build-deno && yarn run build-node",
"build-deno": "denoify && del-cli ../deno --force && move-file deno_dist ../deno && cpy ../../README.md ../deno",
"build": "yarn build-deno && yarn run build-node",
"build-deno": "denoify && del-cli ../deno-core --force && move-file deno_dist ../deno-core && cpy ../../README.md ../deno-core",
"build-node": "del-cli dist && del-cli dist-esm && tsc && tsc -b tsconfig.esm.json && node scripts/esm-post-process.js",
"build-render-graphiql": "cd ../graphiql && yarn run build",
"test": "jest",
"esm:test": "node scripts/test-esm.mjs"
},
Expand Down
2 changes: 1 addition & 1 deletion packages/core/test/implementations/express.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import express, { RequestHandler } from "express";
import { getGraphQLParameters, processRequest, renderGraphiQL, sendResult, shouldRenderGraphiQL } from "../../lib";
import { getGraphQLParameters, processRequest, renderGraphiQL, sendResult, shouldRenderGraphiQL } from "../../../graphql-helix";
Copy link
Contributor

@n1ru4l n1ru4l Dec 2, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should move this folder (test/implementations) to packages/graphql-helix.

import { schema } from "../schema";

const graphqlMiddleware: RequestHandler = async (req, res) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/test/implementations/fastify.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import fastify, { RouteHandlerMethod } from "fastify";
import { getGraphQLParameters, processRequest, renderGraphiQL, sendResult, shouldRenderGraphiQL } from "../../lib";
import { getGraphQLParameters, processRequest, renderGraphiQL, sendResult, shouldRenderGraphiQL } from "../../../graphql-helix";
import { schema } from "../schema";

const graphqlHandler: RouteHandlerMethod = async (req, res) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/test/implementations/fastify_async.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import fastify, { RouteHandlerMethod } from "fastify";
import { parse as graphqlParse } from "graphql";
import { getGraphQLParameters, processRequest, renderGraphiQL, sendResult, shouldRenderGraphiQL } from "../../lib";
import { getGraphQLParameters, processRequest, renderGraphiQL, sendResult, shouldRenderGraphiQL } from "../../../graphql-helix";
import { schema } from "../schema";

const sleep = (time: number) => new Promise<void>((resolve) => setTimeout(resolve, time));
Expand Down
2 changes: 1 addition & 1 deletion packages/core/test/implementations/koa.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Koa, { Context } from "koa";
import bodyParser from "koa-bodyparser";
import { PassThrough } from "stream";
import { getGraphQLParameters, processRequest, renderGraphiQL, shouldRenderGraphiQL } from "../../lib";
import { getGraphQLParameters, processRequest, renderGraphiQL, shouldRenderGraphiQL } from "../../../graphql-helix";
import { schema } from "../schema";

const graphqlHandler = async (ctx: Context) => {
Expand Down
8 changes: 1 addition & 7 deletions packages/core/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,6 @@
"allowSyntheticDefaultImports": true,
"esModuleInterop": true
},
"exclude": [
"deno_dist",
"dist",
"examples",
"node_modules",
"packages/graphql-helix/test"
],
"exclude": ["deno_dist", "dist", "examples", "node_modules"],
"include": ["lib", "declarations.d.ts"]
}
116 changes: 116 additions & 0 deletions packages/deno-core/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<h1 align="center">
<br>
<img width="400" src="./logo.svg" alt="GraphQL Helix">
<br>
<br>
<br>
</h1>

> A highly evolved GraphQL HTTP Server 🧬

GraphQL Helix is a collection of utility functions for building your own GraphQL HTTP server. You can check out [Building a GraphQL server with GraphQL Helix](https://dev.to/danielrearden/building-a-graphql-server-with-graphql-helix-2k44) on DEV for a detailed tutorial on getting started.

## Features

- **Framework and runtime agnostic.** Use whatever HTTP library you want. GraphQL Helix works in Node, Deno and in the browser.
- **HTTP first.** GraphQL Helix allows you to create a [GraphQL over HTTP](https://github.com/graphql/graphql-over-http) specification-compliant server, while exposing a single HTTP endpoint for everything from documentation to subscriptions.
- **Server push and client pull.** GraphQL Helix supports real-time requests with both subscriptions and `@defer` and `@stream` directives.
- **Flexible.** GraphQL Helix abstracts away logic that's common to all GraphQL HTTP servers, while leaving the implementation to you. Implement the features you want and take full control of your transport layer.
- **Minimal.** No bloat. No paid platform integration. Zero dependencies outside of `graphql-js`.

## Installation

```
npm install graphql-helix
```

```
yarn add graphql-helix
```

## Basic Usage

The following example shows how to integrate GraphQL Helix with Node.js using Express. This example shows how to implement all the basic features, including a GraphiQL interface, subscriptions and support for `@stream` and `@defer`. See the rest of the [examples](./examples) for implementations using other frameworks and runtimes. For implementing additional features, see the [Recipes](#Recipes) section below.

```js
import express, { RequestHandler } from "express";
import { getGraphQLParameters, processRequest, renderGraphiQL, shouldRenderGraphiQL, sendResult } from "../lib";
import { schema } from "./schema";

const app = express();

app.use(express.json());

app.use("/graphql", async (req, res) => {
// Create a generic Request object that can be consumed by Graphql Helix's API
const request = {
body: req.body,
headers: req.headers,
method: req.method,
query: req.query,
};

// Determine whether we should render GraphiQL instead of returning an API response
if (shouldRenderGraphiQL(request)) {
res.send(renderGraphiQL());
} else {
// Extract the Graphql parameters from the request
const { operationName, query, variables } = getGraphQLParameters(request);

// Validate and execute the query
const result = await processRequest({
operationName,
query,
variables,
request,
schema,
});

// processRequest returns one of three types of results depending on how the server should respond
// 1) RESPONSE: a regular JSON payload
// 2) MULTIPART RESPONSE: a multipart response (when @stream or @defer directives are used)
// 3) PUSH: a stream of events to push back down the client for a subscription
// The "sendResult" is a NodeJS-only shortcut for handling all possible types of Graphql responses,
// See "Advanced Usage" below for more details and customizations available on that layer.
sendResult(result, res);
}
});

const port = process.env.PORT || 4000;

app.listen(port, () => {
console.log(`GraphQL server is running on port ${port}.`);
});
```

## Transports Variations

The `processRequest` will return one of the following types:

- `RESPONSE`: a regular JSON payload
- `MULTIPART_RESPONSE`: a multipart response (when @stream or @defer directives are used)
- `PUSH`: a stream of events to push back down the client for a GraphQL subscription

If you GraphQL schema doesn't have the `type Subscription` defined, or the `@stream` / `@defer` / `@live` directives available, you'll get `RESPONSE` in your result payload, so you can just use `sendResult` helper to send the response data in one line of code.

If you wish to have more control over you transports, you can use one of the following exported helpers:

- `sendResponseResult` - matches the `RESPONSE` type.
- `sendMultipartResponseResult` - matches the `MULTIPART_RESPONSE` type.
- `sendPushResult` - matches the `PUSH` type.

And you'll be able to construct a custom flow. Here's a quick example for customizing the response per each type of result:

```ts
if (result.type === "RESPONSE") {
sendResponseResult(result, res);
} else if (result.type === "MULTIPART_RESPONSE") {
sendMultipartResponseResult(result, res);
} else if (result.type === "PUSH") {
sendPushResult(result, res);
}
```

> This way you can also disable specific responses if you wish, by return an error instead of calling the helpers.

Checkout docs to learn more.
File renamed without changes.
7 changes: 7 additions & 0 deletions packages/deno-core/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export * from "./get-graphql-parameters.ts";
export * from "./process-request.ts";
export * from "./should-render-graphiql.ts";
export * from "./types.ts";
export * from "./errors.ts";
export * from "./send-result/node-http.ts";
export * from "./send-result/w3c.ts";
1 change: 1 addition & 0 deletions packages/deno-core/mod.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./index.ts";
File renamed without changes.
File renamed without changes.
Loading