@freshsqueezed/mammothgql
Advanced tools
Comparing version 1.0.2 to 1.0.3
@@ -0,1 +1,9 @@ | ||
## [1.0.3](https://github.com/freshsqueezed/mammothgql/compare/v1.0.2...v1.0.3) (2024-11-26) | ||
### Bug Fixes | ||
* add new filter function ([fa97bd2](https://github.com/freshsqueezed/mammothgql/commit/fa97bd2629343ee885d782a190f404afc181f9b9)) | ||
* update middleware ([54609c8](https://github.com/freshsqueezed/mammothgql/commit/54609c88b32f1aa21ad695396fff5c02ef3dddf7)) | ||
## [1.0.2](https://github.com/freshsqueezed/mammothgql/compare/v1.0.1...v1.0.2) (2024-11-26) | ||
@@ -2,0 +10,0 @@ |
@@ -1,12 +0,3 @@ | ||
import { NextFunction, Request, Response } from 'express'; | ||
import { GraphQLSchema } from 'graphql'; | ||
export interface MammothOptions<TContext> { | ||
schema: GraphQLSchema; | ||
context: ({ req, res }: { | ||
req: Request; | ||
res: Response; | ||
}) => TContext; | ||
graphiql?: boolean; | ||
} | ||
export default function mammothGraphql<TContext>({ schema, context, graphiql, }: MammothOptions<TContext>): (req: Request, res: Response, next: NextFunction) => Promise<void>; | ||
export * from './mammoth'; | ||
export * from './with-filter'; | ||
//# sourceMappingURL=index.d.ts.map |
"use strict"; | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
var desc = Object.getOwnPropertyDescriptor(m, k); | ||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { | ||
desc = { enumerable: true, get: function() { return m[k]; } }; | ||
} | ||
Object.defineProperty(o, k2, desc); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __exportStar = (this && this.__exportStar) || function(m, exports) { | ||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.default = mammothGraphql; | ||
const graphql_1 = require("graphql"); | ||
const errors_1 = require("./errors"); | ||
const utils_1 = require("./utils"); | ||
const query_1 = require("./query"); | ||
const html_1 = require("./html"); | ||
function mammothGraphql({ schema, context, graphiql = false, }) { | ||
return async (req, res, next) => { | ||
if (!graphiql) { | ||
res.send((0, html_1.disabledLandingPage)()); | ||
return; | ||
} | ||
if (graphiql && req.method === 'GET') { | ||
if (process.env.NODE_ENV !== 'production') { | ||
res.send((0, html_1.graphiqlHtml)()); | ||
} | ||
else { | ||
res.send((0, html_1.customLandingHtml)()); | ||
} | ||
return; | ||
} | ||
const { query, variables } = req.body; | ||
if (!query) { | ||
res | ||
.status(400) | ||
.json({ errors: [new errors_1.ValidationError('No query provided')] }); | ||
return; | ||
} | ||
try { | ||
// Parse and validate the query | ||
const source = new graphql_1.Source(query, 'Mammoth Request'); | ||
const document = (0, graphql_1.parse)(source); | ||
const validationErrors = (0, graphql_1.validate)(schema, document, graphql_1.specifiedRules); | ||
if (validationErrors.length > 0) { | ||
return (0, utils_1.handleValidationErrors)(validationErrors, res); | ||
} | ||
// Prepare context and execute the query | ||
const contextValue = context({ req, res }); | ||
const executionResult = await (0, query_1.executeQuery)(schema, document, contextValue, variables); | ||
// Handle errors in the execution result | ||
if (executionResult.errors && executionResult.errors.length > 0) { | ||
console.error('GraphQL Errors:', executionResult.errors); | ||
const responseErrors = (0, utils_1.formatExecutionErrors)(executionResult.errors); | ||
res.status(200).json({ data: null, errors: responseErrors }); | ||
return; | ||
} | ||
// Return the successful response | ||
res.status(200).json({ | ||
data: executionResult.data, | ||
}); | ||
} | ||
catch (error) { | ||
// Handle unexpected errors | ||
console.error('Server Error:', error); | ||
const message = process.env.NODE_ENV === 'production' | ||
? 'An unexpected error occurred.' | ||
: error instanceof Error | ||
? error.message | ||
: String(error); | ||
res.status(500).json({ errors: [new errors_1.InternalServerError(message)] }); | ||
} | ||
finally { | ||
next(); | ||
} | ||
}; | ||
} | ||
__exportStar(require("./mammoth"), exports); | ||
__exportStar(require("./with-filter"), exports); | ||
//# sourceMappingURL=index.js.map |
@@ -1,2 +0,6 @@ | ||
export declare function executeQuery(schema: any, document: any, contextValue: any, variables: any): Promise<import("graphql").ExecutionResult<import("graphql/jsutils/ObjMap").ObjMap<unknown>, import("graphql/jsutils/ObjMap").ObjMap<unknown>>>; | ||
import { DocumentNode, GraphQLSchema } from 'graphql'; | ||
import { Maybe } from 'graphql/jsutils/Maybe'; | ||
export declare function executeQuery(schema: GraphQLSchema, document: DocumentNode, contextValue: unknown, variables: Maybe<{ | ||
readonly [variable: string]: unknown; | ||
}>): Promise<import("graphql").ExecutionResult<import("graphql/jsutils/ObjMap").ObjMap<unknown>, import("graphql/jsutils/ObjMap").ObjMap<unknown>>>; | ||
//# sourceMappingURL=query.d.ts.map |
@@ -18,5 +18,5 @@ "use strict"; | ||
? error.message | ||
: "Unknown error during query execution"); | ||
: 'Unknown error during query execution'); | ||
} | ||
} | ||
//# sourceMappingURL=query.js.map |
@@ -6,3 +6,3 @@ { | ||
"types": "lib/index.d.ts", | ||
"version": "1.0.2", | ||
"version": "1.0.3", | ||
"author": "Matt Gordon <matt@lemonade.tech>", | ||
@@ -37,4 +37,8 @@ "license": "MIT", | ||
"@types/node": "^22.9.4", | ||
"@types/supertest": "^6.0.2", | ||
"husky": "^9.1.7", | ||
"jest": "^29.7.0", | ||
"prettier": "^3.3.3", | ||
"semantic-release": "^24.2.0", | ||
"supertest": "^7.0.0", | ||
"ts-jest": "^29.2.5", | ||
@@ -41,0 +45,0 @@ "ts-node": "^10.9.2", |
@@ -1,3 +0,65 @@ | ||
# Mammoth GQL | ||
[![@freshsqueezed/mammothgql](https://github.com/freshsqueezed/mammothgql/actions/workflows/release-package.yml/badge.svg)](https://github.com/freshsqueezed/mammothgql/actions/workflows/release-package.yml) | ||
# The 🐝 knees | ||
# `@freshsqueezed/mammothgql` | ||
## A TypeScript/JavaScript GraphQL middleware for `express` | ||
## Getting started: Express middleware | ||
Mammoth GQL enables the ability to add middleware that lets you run your GraphQL server as part of an app built with Express, one of the most popular web frameworks for Node. | ||
First, install MammothGQL Middleware, the JavaScript implementation of the core GraphQL algorithms, Express, and two common Express middleware packages: | ||
``` | ||
npm install @afreshsqueezed/mammothgql graphql @graphql-tools/schema express cors | ||
``` | ||
Then, write the following to `./src/app.ts`. | ||
```ts | ||
import express, { json } from 'express'; | ||
import cors from 'cors'; | ||
import mammoth from '@freshsqueezed/mammothgql'; | ||
import { ServerContext } from './types'; | ||
import schema from './graphql'; | ||
const app = express(); | ||
app.use(cors()); | ||
app.use(json()); | ||
app.use( | ||
'/graphql', | ||
mammoth<ServerContext>({ | ||
schema, | ||
graphiql: true, | ||
context: ({ req }) => ({ | ||
user: req.user || null, | ||
}), | ||
}), | ||
); | ||
export default app; | ||
``` | ||
Create a `./src/index.ts` file and | ||
```ts | ||
import { createServer } from 'node:http'; | ||
import app from './app'; | ||
const httpServer = createServer(app); | ||
httpServer.listen(3000, () => { | ||
console.log(` | ||
🚀 Server is running on http://localhost:${PORT}/graphql | ||
`); | ||
}); | ||
``` | ||
Now run your server with: | ||
``` | ||
ts-node ./src/index.ts | ||
``` | ||
Open the URL it prints in a web browser. It will show GraphiQL, a web-based tool for running GraphQL operations. Try running the operation `query { hello }`! |
105
src/index.ts
@@ -1,103 +0,2 @@ | ||
import { NextFunction, Request, Response } from 'express'; | ||
import { | ||
ExecutionResult, | ||
GraphQLSchema, | ||
parse, | ||
Source, | ||
specifiedRules, | ||
validate, | ||
} from 'graphql'; | ||
import { InternalServerError, ValidationError } from './errors'; | ||
import { formatExecutionErrors, handleValidationErrors } from './utils'; | ||
import { executeQuery } from './query'; | ||
import { customLandingHtml, disabledLandingPage, graphiqlHtml } from './html'; | ||
export interface MammothOptions<TContext> { | ||
schema: GraphQLSchema; | ||
context: ({ req, res }: { req: Request; res: Response }) => TContext; | ||
graphiql?: boolean; | ||
} | ||
export default function mammothGraphql<TContext>({ | ||
schema, | ||
context, | ||
graphiql = false, | ||
}: MammothOptions<TContext>) { | ||
return async ( | ||
req: Request, | ||
res: Response, | ||
next: NextFunction, | ||
): Promise<void> => { | ||
if (!graphiql) { | ||
res.send(disabledLandingPage()); | ||
return; | ||
} | ||
if (graphiql && req.method === 'GET') { | ||
if (process.env.NODE_ENV !== 'production') { | ||
res.send(graphiqlHtml()); | ||
} else { | ||
res.send(customLandingHtml()); | ||
} | ||
return; | ||
} | ||
const { query, variables } = req.body; | ||
if (!query) { | ||
res | ||
.status(400) | ||
.json({ errors: [new ValidationError('No query provided')] }); | ||
return; | ||
} | ||
try { | ||
// Parse and validate the query | ||
const source = new Source(query, 'Mammoth Request'); | ||
const document = parse(source); | ||
const validationErrors = validate(schema, document, specifiedRules); | ||
if (validationErrors.length > 0) { | ||
return handleValidationErrors(validationErrors, res); | ||
} | ||
// Prepare context and execute the query | ||
const contextValue: TContext = context({ req, res }); | ||
const executionResult: ExecutionResult = await executeQuery( | ||
schema, | ||
document, | ||
contextValue, | ||
variables, | ||
); | ||
// Handle errors in the execution result | ||
if (executionResult.errors && executionResult.errors.length > 0) { | ||
console.error('GraphQL Errors:', executionResult.errors); | ||
const responseErrors = formatExecutionErrors(executionResult.errors); | ||
res.status(200).json({ data: null, errors: responseErrors }); | ||
return; | ||
} | ||
// Return the successful response | ||
res.status(200).json({ | ||
data: executionResult.data, | ||
}); | ||
} catch (error) { | ||
// Handle unexpected errors | ||
console.error('Server Error:', error); | ||
const message = | ||
process.env.NODE_ENV === 'production' | ||
? 'An unexpected error occurred.' | ||
: error instanceof Error | ||
? error.message | ||
: String(error); | ||
res.status(500).json({ errors: [new InternalServerError(message)] }); | ||
} finally { | ||
next(); | ||
} | ||
}; | ||
} | ||
export * from './mammoth'; | ||
export * from './with-filter'; |
@@ -1,9 +0,12 @@ | ||
import { execute } from "graphql"; | ||
import { InternalServerError } from "./errors"; | ||
import { DocumentNode, execute, GraphQLSchema } from 'graphql'; | ||
import { InternalServerError } from './errors'; | ||
import { Maybe } from 'graphql/jsutils/Maybe'; | ||
export async function executeQuery( | ||
schema: any, | ||
document: any, | ||
contextValue: any, | ||
variables: any | ||
schema: GraphQLSchema, | ||
document: DocumentNode, | ||
contextValue: unknown, | ||
variables: Maybe<{ | ||
readonly [variable: string]: unknown; | ||
}>, | ||
) { | ||
@@ -21,5 +24,5 @@ try { | ||
? error.message | ||
: "Unknown error during query execution" | ||
: 'Unknown error during query execution', | ||
); | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
53907
60
1076
66
16