diff --git a/packages/graph-explorer-proxy-server/src/node-server.ts b/packages/graph-explorer-proxy-server/src/node-server.ts index 8d96bcd78..ada75e6ce 100644 --- a/packages/graph-explorer-proxy-server/src/node-server.ts +++ b/packages/graph-explorer-proxy-server/src/node-server.ts @@ -27,6 +27,7 @@ interface DbQueryIncomingHttpHeaders extends IncomingHttpHeaders { "aws-neptune-region"?: string; "service-type"?: string; "db-query-logging-enabled"?: string; + "sparql-endpoint-path"?: string; } interface LoggerIncomingHttpHeaders extends IncomingHttpHeaders { @@ -202,6 +203,7 @@ app.post("/sparql", async (req, res, next) => { const headers = req.headers as DbQueryIncomingHttpHeaders; const queryId = headers["queryid"]; const graphDbConnectionUrl = headers["graph-db-connection-url"]; + const sparqlEndpointPath = headers["sparql-endpoint-path"] || "/sparql"; const shouldLogDbQuery = BooleanStringSchema.default(false).parse( headers["db-query-logging-enabled"], ); @@ -219,7 +221,7 @@ app.post("/sparql", async (req, res, next) => { proxyLogger.debug(`Cancelling request ${queryId}...`); try { await retryFetch( - new URL(`${graphDbConnectionUrl}/sparql/status`), + new URL(`${graphDbConnectionUrl}${sparqlEndpointPath}/status`), { method: "POST", headers: { @@ -264,7 +266,7 @@ app.post("/sparql", async (req, res, next) => { proxyLogger.debug("[SPARQL] Received database query:\n%s", queryString); } - const rawUrl = `${graphDbConnectionUrl}/sparql`; + const rawUrl = `${graphDbConnectionUrl}${sparqlEndpointPath}`; let body = `query=${encodeURIComponent(queryString)}`; if (queryId) { body += `&queryId=${encodeURIComponent(queryId)}`; diff --git a/packages/graph-explorer/src/connector/fetchDatabaseRequest.ts b/packages/graph-explorer/src/connector/fetchDatabaseRequest.ts index bf7f0fa39..6941a8cb7 100644 --- a/packages/graph-explorer/src/connector/fetchDatabaseRequest.ts +++ b/packages/graph-explorer/src/connector/fetchDatabaseRequest.ts @@ -69,6 +69,9 @@ function getAuthHeaders( headers["db-query-logging-enabled"] = String( featureFlags.allowLoggingDbQuery, ); + if (connection.sparqlEndpointPath) { + headers["sparql-endpoint-path"] = connection.sparqlEndpointPath; + } } if (connection.awsAuthEnabled) { headers["aws-neptune-region"] = connection.awsRegion || ""; diff --git a/packages/graph-explorer/src/connector/sparql/sparqlExplorer.ts b/packages/graph-explorer/src/connector/sparql/sparqlExplorer.ts index 44160068d..b293049fa 100644 --- a/packages/graph-explorer/src/connector/sparql/sparqlExplorer.ts +++ b/packages/graph-explorer/src/connector/sparql/sparqlExplorer.ts @@ -54,7 +54,7 @@ function _sparqlFetch( return fetchDatabaseRequest( connection, featureFlags, - `${connection.url}/sparql`, + `${connection.url}${connection.sparqlEndpointPath ?? "/sparql"}`, { method: "POST", headers, diff --git a/packages/graph-explorer/src/core/defaultConnection.ts b/packages/graph-explorer/src/core/defaultConnection.ts index 93125a636..8f3ff9a62 100644 --- a/packages/graph-explorer/src/core/defaultConnection.ts +++ b/packages/graph-explorer/src/core/defaultConnection.ts @@ -21,6 +21,8 @@ export const DefaultConnectionDataSchema = z.object({ .enum(neptuneServiceTypeOptions) .default(DEFAULT_SERVICE_TYPE) .catch(DEFAULT_SERVICE_TYPE), + // SPARQL options + GRAPH_EXP_SPARQL_ENDPOINT_PATH: z.string().optional(), // Connection options GRAPH_EXP_FETCH_REQUEST_TIMEOUT: z.number().default(240000), GRAPH_EXP_NODE_EXPANSION_LIMIT: z.number().optional(), @@ -116,6 +118,7 @@ export function mapToConnection(data: DefaultConnectionData): RawConfiguration { awsAuthEnabled: data.GRAPH_EXP_IAM, awsRegion: data.GRAPH_EXP_AWS_REGION, serviceType: data.GRAPH_EXP_SERVICE_TYPE, + sparqlEndpointPath: data.GRAPH_EXP_SPARQL_ENDPOINT_PATH, fetchTimeoutMs: data.GRAPH_EXP_FETCH_REQUEST_TIMEOUT, nodeExpansionLimit: data.GRAPH_EXP_NODE_EXPANSION_LIMIT, }, diff --git a/packages/graph-explorer/src/modules/CreateConnection/CreateConnection.tsx b/packages/graph-explorer/src/modules/CreateConnection/CreateConnection.tsx index b5f7b6e96..c21cf1acf 100644 --- a/packages/graph-explorer/src/modules/CreateConnection/CreateConnection.tsx +++ b/packages/graph-explorer/src/modules/CreateConnection/CreateConnection.tsx @@ -43,6 +43,7 @@ type ConnectionForm = { awsAuthEnabled?: boolean; serviceType?: NeptuneServiceType; awsRegion?: string; + sparqlEndpointPath?: string; fetchTimeoutEnabled: boolean; fetchTimeoutMs?: number; nodeExpansionLimitEnabled: boolean; @@ -72,6 +73,7 @@ function mapToConnection(data: Required): ConnectionConfig { awsAuthEnabled: data.awsAuthEnabled, serviceType: data.serviceType, awsRegion: data.awsRegion, + sparqlEndpointPath: data.sparqlEndpointPath || undefined, fetchTimeoutMs: data.fetchTimeoutEnabled ? data.fetchTimeoutMs : undefined, nodeExpansionLimit: data.nodeExpansionLimitEnabled ? data.nodeExpansionLimit @@ -275,6 +277,25 @@ const CreateConnection = ({ disabled={form.serviceType === "neptune-graph"} /> + {form.queryEngine === "sparql" && ( + + + + + )}