From 135aa2f0dcb5119475a7bbb44ddc28e89b327782 Mon Sep 17 00:00:00 2001 From: Travis Frank Date: Wed, 2 Sep 2020 10:35:07 -0400 Subject: [PATCH 1/2] Implemented GraphQL Router w/o database connection --- demo/server.tsx | 62 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/demo/server.tsx b/demo/server.tsx index b7bd970..0e7ca90 100644 --- a/demo/server.tsx +++ b/demo/server.tsx @@ -1,4 +1,5 @@ -import { Application, Router } from "https://deno.land/x/oak@v6.0.1/mod.ts"; +import { Application, Router, RouterContext } from "https://deno.land/x/oak@v6.0.1/mod.ts"; +import { applyGraphQL, gql, GQLError } from "https://deno.land/x/oak_graphql/mod.ts"; import React from "https://dev.jspm.io/react@16.13.1"; import ReactDomServer from "https://dev.jspm.io/react-dom@16.13.1/server"; @@ -7,6 +8,20 @@ import App from "./app.tsx"; // Create a new server const app = new Application(); +// Track response time in headers of responses +app.use(async (ctx, next) => { + await next(); + const rt = ctx.response.headers.get("X-Response-Time"); + console.log(`${ctx.request.method} ${ctx.request.url} - ${rt}`); +}); + +app.use(async (ctx, next) => { + const start = Date.now(); + await next(); + const ms = Date.now() - start; + ctx.response.headers.set("X-Response-Time", `${ms}ms`); +}); + // Initial state const initialState = {}; @@ -68,6 +83,51 @@ app.use(serverrouter.routes()); app.use(router.allowedMethods()); +// GraphQL types +const types = (gql as any)` +type Book { + title: String + author: String + description: String + coverPrice: Int + publicationDate: String + publisher: String +} + +type ResolveType { + done: Boolean +} + +type Query { + getBook(id: String): Book +} +`; + +// GraphQL Resolvers (For now just the basic getBooks query) +const resolvers = { + Query: { + getBook: (parent: any, { id }: any, context: any, info: any) => { + console.log("id", id, context); + return { + title: "Let's Go!", + author: "Jeho", + }; + }, + }, +}; + +// Setup GraphQL Router +const GraphQLService = await applyGraphQL({ + Router, + typeDefs: types, + resolvers: resolvers, + context: (ctx: RouterContext) => { + return { user: "Aaron" }; + } +}); +app.use(GraphQLService.routes(), GraphQLService.allowedMethods()); + + // Spin up the server console.log("server is running on http://localhost:8000/"); await app.listen({ port: 8000 }); From f212976ad17d4efc62fe1a4555e9af7e7f235f22 Mon Sep 17 00:00:00 2001 From: Travis Frank Date: Wed, 2 Sep 2020 11:28:52 -0400 Subject: [PATCH 2/2] Working GraphQL endpoint --- demo/server.tsx | 67 +++++++++++++++-------------------------------- demo/sqlclient.ts | 10 +++++++ 2 files changed, 31 insertions(+), 46 deletions(-) create mode 100644 demo/sqlclient.ts diff --git a/demo/server.tsx b/demo/server.tsx index 0e7ca90..9fd06db 100644 --- a/demo/server.tsx +++ b/demo/server.tsx @@ -1,5 +1,6 @@ import { Application, Router, RouterContext } from "https://deno.land/x/oak@v6.0.1/mod.ts"; import { applyGraphQL, gql, GQLError } from "https://deno.land/x/oak_graphql/mod.ts"; +import client from "./sqlclient.ts"; import React from "https://dev.jspm.io/react@16.13.1"; import ReactDomServer from "https://dev.jspm.io/react-dom@16.13.1/server"; @@ -29,44 +30,6 @@ const initialState = {}; const router = new Router(); router.get("/", handlePage); -/* - -let todos: Map = new Map(); - -function init() { - todos.set(todos.size + 1, { id: Date.now(), task: "build an ssr deno app" }); - todos.set(todos.size + 1, { - id: Date.now(), - task: "write blogs on deno ssr", - }); -} -init(); -router - .get("/todos", (context) => { - context.response.body = Array.from(todos.values()); - }) - .get("/todos/:id", (context) => { - if ( - context.params && - context.params.id && - todos.has(Number(context.params.id)) - ) { - context.response.body = todos.get(Number(context.params.id)); - } else { - context.response.status = 404; - } - }) - .post("/todos", async (context) => { - const body = context.request.body(); - if (body.type === "json") { - const todo = await body.value; - todos.set(Date.now(), todo); - } - context.response.body = { status: "OK" }; - }); - - */ - // Bundle the client-side code const [_, clientJS] = await Deno.bundle("./client.tsx"); @@ -80,12 +43,12 @@ serverrouter.get("/static/client.js", (context) => { // Implement the routes on the server app.use(router.routes()); app.use(serverrouter.routes()); - app.use(router.allowedMethods()); // GraphQL types const types = (gql as any)` type Book { + id: ID title: String author: String description: String @@ -99,19 +62,31 @@ type ResolveType { } type Query { - getBook(id: String): Book + getBook(id: ID): Book } `; // GraphQL Resolvers (For now just the basic getBooks query) const resolvers = { Query: { - getBook: (parent: any, { id }: any, context: any, info: any) => { + getBook: async (parent: any, { id }: any, context: any, info: any) => { console.log("id", id, context); - return { - title: "Let's Go!", - author: "Jeho", - }; + const data = await client.query(` + SELECT * + FROM books + WHERE id = $1 + `, id); + console.log("Returned rows:"); + console.log(data.rows); + const book = { + title: data.rows[0][1], + author: data.rows[0][2], + description: data.rows[0][3], + coverPrice: data.rows[0][4], + publicationDate: data.rows[0][5], + publisher: data.rows[0][6] + } + return book; }, }, }; @@ -136,7 +111,7 @@ await app.listen({ port: 8000 }); function handlePage(ctx: any) { try { - const body = ReactDomServer.renderToString( + const body = (ReactDomServer as any).renderToString( // Pass state as props here ); ctx.response.body = ` diff --git a/demo/sqlclient.ts b/demo/sqlclient.ts new file mode 100644 index 0000000..e761f4c --- /dev/null +++ b/demo/sqlclient.ts @@ -0,0 +1,10 @@ +import { Client } from "https://deno.land/x/postgres/mod.ts"; + +// Create a new client +const config = "postgres://zjxjnswd:Wh7KJIyXiEy5QyhzXUMK38ykEtYH_9QZ@lallah.db.elephantsql.com:5432/zjxjnswd"; +const client = new Client(config); + +// Connect it +await client.connect(); + +export default client;