Skip to content

Commit

Permalink
feat: built-in endpoint handler
Browse files Browse the repository at this point in the history
  • Loading branch information
vicary committed Apr 13, 2024
1 parent 448977c commit c68f517
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 39 deletions.
34 changes: 13 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ A simple GraphQL server for Deno Fresh.

## Why `fresh-graphql`?

1. Familiar developer experience with `fresh` projects.
1. `deno deploy` has no dynamic imports.
1. [`tRPC`](https://trpc.io) doesn't support deno (yet).
1. You want file based routing.
1. You want GraphQL.
1. You have a [Deno Fresh](https://fresh.deno.dev) project.
1. `deno deploy` does not support dynamic imports.

## Installation

Expand Down Expand Up @@ -54,36 +55,27 @@ await dev(import.meta.url, "./main.ts");

## Usage

1. Run `deno task start`
1. Visit `http://localhost:3000/graphql` for an GraphiQL interface.

### Entrypoint

Any data handler routes would work, the example below uses the pathname
`/graphql` as a convension.
Our CLI will generate a default GraphQL endpoint for you, you may also do it
manually by copying the contents below:

```ts
// routes/graphql.ts

import { type FreshContext } from "$fresh/server.ts";
import { fromManifest } from "@vicary/fresh-graphql";
import { createYoga } from "graphql-yoga";
import { createHandler } from "@vicary/fresh-graphql";
import manifest from "../graphql.gen.ts";

// FRSH_GQL_DEV is set when you start the GraphQL development server in dev.ts.
const debug = Deno.env.has("FRSH_GQL_DEV");

const yoga = createYoga<FreshContext>({
graphiql: debug,
logging: debug,
maskedErrors: !debug,
schema: fromManifest(manifest),
});

export const handler = async (req: Request, ctx: FreshContext) => {
return await yoga.handleRequest(req, ctx);
};
export const handler = createHandler(manifest);
```

### Queries and Mutations

This is a GraphQL version of the joke API when you create a new Fresh project.

```ts
// graphql/Query/joke.ts

Expand Down
26 changes: 26 additions & 0 deletions cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@ async function main() {
log.error("Unable to patch deno.json, please try to do it manually.");
}
}

if (promptYesNo("Create default GraphQL endpoint at routes/graphql?", true)) {
if (!await createEndpoint("routes/graphql.ts")) {
log.error(
"Unable to create routes/graphql.ts, please try to do it manually.",
);
}
}
}

await main();
Expand Down Expand Up @@ -202,3 +210,21 @@ async function patchDenoJson(): Promise<boolean> {

return true;
}

async function createEndpoint(path: string) {
try {
await Deno.writeTextFile(
path,
`// ${path}: GraphQL endpoint for fresh-graphql
import { createHandler } from "@vicary/fresh-graphql";
import manifest from "../graphql.gen.ts";
export const handler = createHandler(manifest);
`,
);
} catch {
return false;
}

return true;
}
2 changes: 1 addition & 1 deletion deno.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@vicary/fresh-graphql",
"version": "0.2.9",
"version": "0.2.10-alpha.0",
"exports": "./mod.ts",
"publish": {
"exclude": [
Expand Down
2 changes: 2 additions & 0 deletions deps.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export type { FreshContext } from "https://deno.land/x/fresh@1.6.8/server.ts";
export { assert } from "jsr:@std/assert@^0.219.1/assert";
export * as colors from "jsr:@std/fmt@^0.219.1/colors";
export { ensureDir } from "jsr:@std/fs@^0.219.1/ensure_dir";
Expand Down Expand Up @@ -32,6 +33,7 @@ export {
type SchemaMapper,
type UnionTypeMapper,
} from "npm:@graphql-tools/utils@^10.1.0";
export { createYoga } from "npm:graphql-yoga@^5.3.0";
export {
defaultFieldResolver,
type DirectiveDefinitionNode,
Expand Down
18 changes: 2 additions & 16 deletions examples/graphql-yoga/routes/graphql.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,4 @@
import { type FreshContext } from "$fresh/server.ts";
import { fromManifest } from "@vicary/fresh-graphql";
import { createYoga } from "graphql-yoga";
import { createHandler } from "@vicary/fresh-graphql";
import manifest from "../graphql.gen.ts";

// FRSH_GQL_DEV is set when you start the GraphQL development server in dev.ts.
const debug = Deno.env.has("FRSH_GQL_DEV");

const yoga = createYoga<FreshContext>({
graphiql: debug,
logging: debug,
maskedErrors: !debug,
schema: fromManifest(manifest),
});

export const handler = async (req: Request, ctx: FreshContext) => {
return await yoga.handleRequest(req, ctx);
};
export const handler = createHandler(manifest);
1 change: 1 addition & 0 deletions mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export {
type GraphQLTypeModule,
type Manifest,
} from "./schema.ts";
export { createHandler } from "./server.ts";

// Start interactive shell that automatically patches the fresh project.
if (import.meta.main) {
Expand Down
2 changes: 1 addition & 1 deletion schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
type InterfaceTypeMapper,
type IResolvers,
makeExecutableSchema,
MapperKind,
type MapperKind,
mapSchema,
type ObjectTypeMapper,
type ScalarTypeMapper,
Expand Down
26 changes: 26 additions & 0 deletions server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { createYoga, type FreshContext } from "./deps.ts";
import type { Manifest } from "./schema.ts";
import { fromManifest } from "./schema.ts";

export type CreateHandlerOptions = {
debug?: boolean;
};

export function createHandler<TManifest extends Manifest>(
manifest: TManifest,
options?: CreateHandlerOptions,
) {
// FRSH_GQL_DEV is set when you start the GraphQL development server in dev.ts.
const debug = options?.debug ?? Deno.env.has("FRSH_GQL_DEV");

const yoga = createYoga<FreshContext>({
graphiql: debug,
logging: debug,
maskedErrors: !debug,
schema: fromManifest(manifest),
});

return async (req: Request, ctx: FreshContext) => {
return await yoga.handleRequest(req, ctx);
};
}

1 comment on commit c68f517

@deno-deploy
Copy link

@deno-deploy deno-deploy bot commented on c68f517 Apr 13, 2024

Choose a reason for hiding this comment

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

Failed to deploy:

BOOT_FAILURE

Uncaught SyntaxError: The requested module '@vicary/fresh-graphql' does not provide an export named 'createHandler'
    at file:///src/examples/graphql-yoga/routes/graphql.ts:1:10

Please sign in to comment.