-
-
Notifications
You must be signed in to change notification settings - Fork 584
Added whatwg-node-server adapter for grafserv #2288
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
base: main
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,7 @@ import type { AddressInfo } from "node:net"; | |
import { constant, error, makeGrafastSchema } from "grafast"; | ||
import { resolvePreset } from "graphile-config"; | ||
|
||
import { grafserv } from "../src/servers/node/index.js"; | ||
import { grafserv } from "../src/servers/whtatwg-node-server"; | ||
|
||
export async function makeExampleServer( | ||
preset: GraphileConfig.Preset = { | ||
|
@@ -36,8 +36,7 @@ export async function makeExampleServer( | |
}); | ||
|
||
const serv = grafserv({ schema, preset }); | ||
const server = createServer(); | ||
serv.addTo(server); | ||
const server = createServer(serv.createHandler()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please don't make this change, it does not handle websockets and other concerns. It means that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure this would work, wouldn't that make the WHATWG adapter reliant on node types? For now I changed the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I think Lambda does not support
Are there alternatives to |
||
const promise = new Promise<void>((resolve, reject) => { | ||
server.on("listening", () => { | ||
server.off("error", reject); | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,115 @@ | ||||||||||||||||||||
import { createServerAdapter } from '@whatwg-node/server' | ||||||||||||||||||||
|
||||||||||||||||||||
import { GrafservBase } from "../../core/base.js"; | ||||||||||||||||||||
import type { | ||||||||||||||||||||
GrafservConfig, | ||||||||||||||||||||
RequestDigest, | ||||||||||||||||||||
Result, | ||||||||||||||||||||
} from "../../interfaces.js"; | ||||||||||||||||||||
|
||||||||||||||||||||
declare global { | ||||||||||||||||||||
// eslint-disable-next-line @typescript-eslint/no-namespace | ||||||||||||||||||||
namespace Grafast { | ||||||||||||||||||||
interface RequestContext { | ||||||||||||||||||||
whatwg: { | ||||||||||||||||||||
request: Request | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
/** @experimental */ | ||||||||||||||||||||
export class WhatwgGrafserv extends GrafservBase { | ||||||||||||||||||||
protected whatwgRequestToGrafserv( | ||||||||||||||||||||
request: Request | ||||||||||||||||||||
): RequestDigest { | ||||||||||||||||||||
const url = new URL(request.url); | ||||||||||||||||||||
return { | ||||||||||||||||||||
httpVersionMajor: 1, | ||||||||||||||||||||
httpVersionMinor: 0, | ||||||||||||||||||||
benjie marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||
isSecure: url.protocol === 'https://', | ||||||||||||||||||||
benjie marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||
method: request.method, | ||||||||||||||||||||
path: url.pathname, | ||||||||||||||||||||
headers: this.processHeaders(request.headers), | ||||||||||||||||||||
getQueryParams() { | ||||||||||||||||||||
return Object.fromEntries(url.searchParams.entries()) as Record<string, string>; | ||||||||||||||||||||
}, | ||||||||||||||||||||
async getBody() { | ||||||||||||||||||||
const text = await request.text() | ||||||||||||||||||||
return { | ||||||||||||||||||||
type: "text", | ||||||||||||||||||||
text, | ||||||||||||||||||||
}; | ||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are we certain the body will always be text? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tried changing this based on the other adapters, let me know if this looks better. |
||||||||||||||||||||
}, | ||||||||||||||||||||
requestContext: { | ||||||||||||||||||||
whatwg: {request} | ||||||||||||||||||||
benjie marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||
}, | ||||||||||||||||||||
preferJSON: true, | ||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Disappointing, this opts out of some performance enhancements. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm honestly not sure about this. How can I tell if this can be set to false? |
||||||||||||||||||||
}; | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
protected processHeaders(headers: Headers): Record<string, string> { | ||||||||||||||||||||
const headerDigest: Record<string, string> = Object.create(null); | ||||||||||||||||||||
headers.forEach((v,k)=> { | ||||||||||||||||||||
headerDigest[k]= v | ||||||||||||||||||||
}) | ||||||||||||||||||||
return headerDigest | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
protected grafservResponseToWhatwg(response: Result | null): Response { | ||||||||||||||||||||
if (response === null) { | ||||||||||||||||||||
return new Response("¯\\_(ツ)_/¯", {status: 404, headers: new Headers({"Content-Type": "text/plain"})}) | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
switch (response.type) { | ||||||||||||||||||||
case "error": { | ||||||||||||||||||||
const { statusCode, headers, error } = response; | ||||||||||||||||||||
const respHeaders = new Headers(headers) | ||||||||||||||||||||
respHeaders.append("Content-Type", "text/plain") | ||||||||||||||||||||
return new Response(error.message, {status: statusCode, headers:respHeaders}) | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
case "buffer": { | ||||||||||||||||||||
const { statusCode, headers, buffer } = response; | ||||||||||||||||||||
const respHeaders = new Headers(headers) | ||||||||||||||||||||
return new Response(buffer.toString('utf8'), {status: statusCode, headers:respHeaders}) | ||||||||||||||||||||
benjie marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
case "json": { | ||||||||||||||||||||
const { statusCode, headers, json } = response; | ||||||||||||||||||||
const respHeaders = new Headers(headers) | ||||||||||||||||||||
return new Response(JSON.stringify(json), {status: statusCode, headers:respHeaders}) | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
default: { | ||||||||||||||||||||
console.log("Unhandled:"); | ||||||||||||||||||||
console.dir(response); | ||||||||||||||||||||
return new Response("Server hasn't implemented this yet", {status: 501, headers: new Headers({"Content-Type": "text/plain"})}) | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
createHandler() { | ||||||||||||||||||||
// eslint-disable-next-line @typescript-eslint/no-this-alias | ||||||||||||||||||||
return createServerAdapter(async (request: Request): Promise<Response> => { | ||||||||||||||||||||
return this.grafservResponseToWhatwg( | ||||||||||||||||||||
await this.processWhatwgRequest( | ||||||||||||||||||||
request, | ||||||||||||||||||||
this.whatwgRequestToGrafserv(request), | ||||||||||||||||||||
), | ||||||||||||||||||||
); | ||||||||||||||||||||
}) | ||||||||||||||||||||
} | ||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please also implement an crystal/grafast/grafserv/src/servers/node/index.ts Lines 290 to 298 in 36c41e8
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See this comment #2288 (comment) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a common interface that all the servers support that would allow for this? I'd rather consistency if possible, but if we have to do it a different way for this one adaptor that's fine. Another option would be to have |
||||||||||||||||||||
|
||||||||||||||||||||
protected processWhatwgRequest( | ||||||||||||||||||||
_request: Request, | ||||||||||||||||||||
request: RequestDigest, | ||||||||||||||||||||
) { | ||||||||||||||||||||
return this.processRequest(request); | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
/** @experimental */ | ||||||||||||||||||||
export function grafserv(config: GrafservConfig) { | ||||||||||||||||||||
return new WhatwgGrafserv(config); | ||||||||||||||||||||
} |
Uh oh!
There was an error while loading. Please reload this page.