Skip to content

Commit 51f0eca

Browse files
authored
Merge pull request #122 from dolthub/taylor/graphql-host
web: Support GraphQL api url environment variable
2 parents 6890e50 + a27bb28 commit 51f0eca

File tree

8 files changed

+127
-8
lines changed

8 files changed

+127
-8
lines changed

docker/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ FROM web-base AS web-deps
4949
RUN apk add --no-cache libc6-compat
5050
WORKDIR /app/web
5151

52-
# Copy the package.json and package-lock.json files
52+
# Copy the package.json and yarn.lock files
5353
COPY web/yarn.lock web/package.json web/.yarnrc.yml ./
5454

5555
# Install dependencies

docker/README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,17 @@ yourself:
8282
CREATE DATABASE dolt_workbench;
8383
```
8484

85+
### Specifying a different GraphQL API URL
86+
87+
When running this Docker image locally, GraphQL API requests are routed to the GraphQL
88+
server running at `http://localhost:9002/graphql`. In some cases you may want to specify a
89+
different url to route GraphQL API requests, and you can do so using the following
90+
environment variable:
91+
92+
```bash
93+
% docker run -p 9002:9002 -p 3000:3000 -e GRAPHQLAPI_URL="[your-host]:9002/graphql" dolthub/dolt-workbench:latest
94+
```
95+
8596
## Connecting to an internet accessible database
8697

8798
If your database is already internet accessible (i.e. your database is hosted on a service like [AWS RDS](https://aws.amazon.com/rds/) or [Hosted Dolt](https://hosted.doltdb.com)), simply enter your database connection information through the UI.

web/contexts/serverConfig.tsx

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import ErrorMsg from "@components/ErrorMsg";
2+
import Loader from "@components/Loader";
3+
import { createContextWithDisplayName } from "@dolthub/react-contexts";
4+
import { ReactNode, useContext } from "react";
5+
import useSWR from "swr";
6+
import { ServerConfig } from "../pages/api/config";
7+
8+
export type ServerConfigContextValue = Partial<ServerConfig>;
9+
10+
export const ServerConfigContext =
11+
createContextWithDisplayName<ServerConfigContextValue>(
12+
{},
13+
"ServerConfigContext",
14+
);
15+
16+
type Props = {
17+
children: ReactNode;
18+
};
19+
20+
// ServerConfigProvider needs to wrap every page, and is only used in _app
21+
export function ServerConfigProvider({ children }: Props): JSX.Element {
22+
const { data, error } = useSWR<ServerConfigContextValue>("/api/config");
23+
24+
if (error) {
25+
return (
26+
<>
27+
<ErrorMsg err={error} />
28+
{children}
29+
</>
30+
);
31+
}
32+
33+
return data ? (
34+
<ServerConfigContext.Provider value={{ ...data }}>
35+
{children}
36+
</ServerConfigContext.Provider>
37+
) : (
38+
<Loader loaded={false} />
39+
);
40+
}
41+
42+
export function useServerConfig(): ServerConfigContextValue {
43+
return useContext(ServerConfigContext);
44+
}

web/lib/apollo.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { IncomingMessage } from "http";
1010
import fetch from "isomorphic-unfetch";
1111
import { NextPage, NextPageContext } from "next";
1212

13-
const graphqlApiUrl = "http://localhost:9002/graphql";
13+
const defaultGraphqlApiUrl = "http://localhost:9002/graphql";
1414

1515
export function createApolloClient(
1616
uri: string,
@@ -50,6 +50,7 @@ let globalApolloClient: ApolloClient<NormalizedCacheObject> | undefined;
5050
export const initApolloClient = (
5151
initialState?: NormalizedCacheObject,
5252
req?: IncomingMessage,
53+
graphqlApiUrl = defaultGraphqlApiUrl,
5354
): ApolloClient<NormalizedCacheObject> => {
5455
// Make sure to create a new client for every server-side request so that data
5556
// isn't shared between connections (which would be bad)
@@ -108,7 +109,7 @@ export const initOnContext = (ctx: NextPageContext): ContextWithClient => {
108109
*/
109110
export function withApollo<
110111
P extends Record<string, unknown> = Record<string, unknown>,
111-
>() {
112+
>(graphqlApiUrl = defaultGraphqlApiUrl) {
112113
// eslint-disable-next-line @typescript-eslint/naming-convention
113114
return (PageComponent: NextPage<P>) => {
114115
const WithApollo = ({
@@ -122,7 +123,7 @@ export function withApollo<
122123
client = apolloClient;
123124
} else {
124125
// Happens on: next.js csr
125-
client = initApolloClient(apolloState, undefined);
126+
client = initApolloClient(apolloState, undefined, graphqlApiUrl);
126127
}
127128
return (
128129
<ApolloProvider client={client}>

web/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
},
2727
"dependencies": {
2828
"@apollo/client": "^3.7.0",
29+
"@dolthub/react-contexts": "^0.1.0",
2930
"@dolthub/react-hooks": "^0.1.6",
3031
"@dolthub/web-utils": "^0.1.2",
3132
"@react-icons/all-files": "^4.1.0",
@@ -59,6 +60,7 @@
5960
"reactflow": "^11.10.1",
6061
"reactjs-popup": "^2.0.6",
6162
"sharp": "^0.33.1",
63+
"swr": "^2.2.4",
6264
"tailwindcss": "^3.3.5"
6365
},
6466
"devDependencies": {

web/pages/_app.tsx

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,30 @@
11
import "@components/AceEditor/ace-editor.css";
22
import "@components/util/KeyNav/index.css";
3+
import { ServerConfigProvider, useServerConfig } from "@contexts/serverConfig";
34
import { withApollo } from "@lib/apollo";
45
import { colors } from "@lib/tailwind";
56
import "github-markdown-css/github-markdown-light.css";
67
import App from "next/app";
78
import Head from "next/head";
89
import "react-tooltip/dist/react-tooltip.css";
10+
import { SWRConfig } from "swr";
911
import "../styles/global.css";
1012

13+
// configure fetch for use with SWR
14+
const fetcher = async (input: RequestInfo, init: RequestInit) => {
15+
const res = await fetch(input, init);
16+
if (!res.ok) {
17+
throw await res.json();
18+
}
19+
return res.json();
20+
};
21+
22+
function Inner(props: { pageProps: any; Component: any }) {
23+
const { graphqlApiUrl } = useServerConfig();
24+
const WrappedPage = withApollo(graphqlApiUrl)(props.Component);
25+
return <WrappedPage {...props.pageProps} />;
26+
}
27+
1128
export default class DoltSQLWorkbench extends App {
1229
public render() {
1330
const { Component, pageProps, router } = this.props;
@@ -19,7 +36,6 @@ export default class DoltSQLWorkbench extends App {
1936
...router.query,
2037
};
2138

22-
const WrappedPage = withApollo()(Component);
2339
return (
2440
<>
2541
<Head>
@@ -57,7 +73,11 @@ export default class DoltSQLWorkbench extends App {
5773
/>
5874
<meta name="theme-color" content={colors["ld-mediumblue"]} />
5975
</Head>
60-
<WrappedPage {...pageProps} />
76+
<SWRConfig value={{ fetcher }}>
77+
<ServerConfigProvider>
78+
<Inner pageProps={pageProps} Component={Component} />
79+
</ServerConfigProvider>
80+
</SWRConfig>
6181
</>
6282
);
6383
}

web/pages/api/config.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { NextApiHandler } from "next";
2+
3+
const cfg = {
4+
graphqlApiUrl: process.env.GRAPHQLAPI_URL,
5+
};
6+
7+
export type ServerConfig = typeof cfg;
8+
9+
const handler: NextApiHandler = (_req, res) => {
10+
res.statusCode = 200;
11+
res.setHeader("Content-Type", "application/json");
12+
res.end(JSON.stringify(cfg));
13+
};
14+
15+
export default handler;

web/yarn.lock

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1281,6 +1281,7 @@ __metadata:
12811281
resolution: "@dolt-sql-workbench/web@workspace:."
12821282
dependencies:
12831283
"@apollo/client": "npm:^3.7.0"
1284+
"@dolthub/react-contexts": "npm:^0.1.0"
12841285
"@dolthub/react-hooks": "npm:^0.1.6"
12851286
"@dolthub/web-utils": "npm:^0.1.2"
12861287
"@graphql-codegen/cli": "npm:^5.0.0"
@@ -1361,13 +1362,26 @@ __metadata:
13611362
sharp: "npm:^0.33.1"
13621363
stylelint: "npm:^15.11.0"
13631364
stylelint-config-recommended: "npm:^14.0.0"
1365+
swr: "npm:^2.2.4"
13641366
tailwindcss: "npm:^3.3.5"
13651367
ts-jest: "npm:^29.1.1"
13661368
typescript: "npm:^5.2.2"
13671369
yalc: "npm:^1.0.0-pre.53"
13681370
languageName: unknown
13691371
linkType: soft
13701372

1373+
"@dolthub/react-contexts@npm:^0.1.0":
1374+
version: 0.1.0
1375+
resolution: "@dolthub/react-contexts@npm:0.1.0"
1376+
dependencies:
1377+
"@dolthub/react-hooks": "npm:^0.1.6"
1378+
peerDependencies:
1379+
react: ^18.2.0
1380+
react-dom: ^18.2.0
1381+
checksum: 6c28e440d845546440e590887fffc683f210fe761fa6e7dbf0d56063f4ad9825ed991dd4146de9c6d6e6c47b78ee1d234146aaf3d4455f26d755eaf941fabc02
1382+
languageName: node
1383+
linkType: hard
1384+
13711385
"@dolthub/react-hooks@npm:^0.1.6":
13721386
version: 0.1.6
13731387
resolution: "@dolthub/react-hooks@npm:0.1.6"
@@ -5305,7 +5319,7 @@ __metadata:
53055319
languageName: node
53065320
linkType: hard
53075321

5308-
"client-only@npm:0.0.1":
5322+
"client-only@npm:0.0.1, client-only@npm:^0.0.1":
53095323
version: 0.0.1
53105324
resolution: "client-only@npm:0.0.1"
53115325
checksum: 9d6cfd0c19e1c96a434605added99dff48482152af791ec4172fb912a71cff9027ff174efd8cdb2160cc7f377543e0537ffc462d4f279bc4701de3f2a3c4b358
@@ -13054,6 +13068,18 @@ __metadata:
1305413068
languageName: node
1305513069
linkType: hard
1305613070

13071+
"swr@npm:^2.2.4":
13072+
version: 2.2.4
13073+
resolution: "swr@npm:2.2.4"
13074+
dependencies:
13075+
client-only: "npm:^0.0.1"
13076+
use-sync-external-store: "npm:^1.2.0"
13077+
peerDependencies:
13078+
react: ^16.11.0 || ^17.0.0 || ^18.0.0
13079+
checksum: ad7d3205f2b4969f6727b25819f2f999af792083b63a25c54fae10bc841c94827fb06652764ef94fa7a46cf9dda25a41f088809919d070dd0fec5b0005a3e839
13080+
languageName: node
13081+
linkType: hard
13082+
1305713083
"symbol-observable@npm:^4.0.0":
1305813084
version: 4.0.0
1305913085
resolution: "symbol-observable@npm:4.0.0"
@@ -13718,7 +13744,7 @@ __metadata:
1371813744
languageName: node
1371913745
linkType: hard
1372013746

13721-
"use-sync-external-store@npm:1.2.0":
13747+
"use-sync-external-store@npm:1.2.0, use-sync-external-store@npm:^1.2.0":
1372213748
version: 1.2.0
1372313749
resolution: "use-sync-external-store@npm:1.2.0"
1372413750
peerDependencies:

0 commit comments

Comments
 (0)