Gathering detailed insights and metrics for @dreamit/graphql-server
Gathering detailed insights and metrics for @dreamit/graphql-server
Gathering detailed insights and metrics for @dreamit/graphql-server
Gathering detailed insights and metrics for @dreamit/graphql-server
npm install @dreamit/graphql-server
Typescript
Module System
Min. Node Version
Node Version
NPM Version
74.9
Supply Chain
98.4
Quality
92.8
Maintenance
100
Vulnerability
100
License
TypeScript (100%)
Total Downloads
12,109
Last Day
53
Last Week
137
Last Month
472
Last Year
5,587
4 Stars
821 Commits
2 Forks
3 Watching
10 Branches
6 Contributors
Minified
Minified + Gzipped
Latest Version
4.12.2
Package Id
@dreamit/graphql-server@4.12.2
Unpacked Size
329.07 kB
Size
62.62 kB
File Count
11
NPM Version
10.8.2
Node Version
20.18.1
Publised On
13 Dec 2024
Cumulative downloads
Total Downloads
Last day
1,225%
53
Compared to previous day
Last week
-32.5%
137
Compared to previous week
Last month
-24.7%
472
Compared to previous month
Last year
7.6%
5,587
Compared to previous year
3
A GraphQL server implementation written in NodeJS/Typescript. It uses the standard graphql library to receive GraphQL requests and send back appropriate responses.
1npm install --save @dreamit/graphql-server
TypeScript declarations are provided within the project.
The following table shows which version of graphql-js, @dreamit/graphql-server-base and @dreamit/funpara are compatible with which version of
@dreamit/graphql-server
. As @dreamit/graphql-server
defines them as peerDependency you might want to
choose a fitting version used in your project and by other libraries depending
on them.
graphql-js version | graphql-server version | graphql-server-base version | funpara version | Github branch | Development Status |
---|---|---|---|---|---|
end of life | |||||
end of life | |||||
^16.0.0 | 3.x | ^1.0.1 | n.a. | legacy-server-v3 | maintenance |
^16.0.0 | 4.x | ^2.0 | ^1.0 | main | active |
GraphQLServer
provides the function handleRequest
to handle and execute requests.
Depending on the provided parameters different actions will be executed in order to send or return the ExecutionResult
GraphQLServerRequest
the extractInformationFromRequest
function will be used to
extract information from the request (url and/or body) and be available as GraphQLRequestInfo
. If the request already
is a GraphQLRequestInfo
this information will be used without extracting information from the server request.sendResponse
function and
the GraphQLExecutionResult
will be returned. If response is undefined, no response will be sent and
the GraphQLExecutionResult
will be returned.1class GraphQLServer { 2 async handleRequest( 3 request: GraphQLServerRequest | GraphQLRequestInfo, 4 response?: GraphQLServerResponse, 5 ): Promise<GraphQLExecutionResult> {} 6}
The handleRequest
function can be used for many use cases. The following part lists some use cases with a short
description. It is possible to use handleRequest
with different parameters with a single GraphQLServer
instance,
e.g. when using a webserver with websockets or messaging.
handleRequest
with GraphQLServerRequest
and GraphQLServerResponse
: Use as webserver middleware.
Create an instance of GraphQLServer
and use the request
and response provided by the webserver as parameters. You might need to wrap one or both values,
see Webserver compatibilityhandleRequest
with GraphQLRequestInfo
: Use for flexible GraphQL execution, e.g. for websockets or messaging.
Create an instance of GraphQLServer
and given a GraphQLRequestInfo
the request can be executed and the returned
GraphQLExecutionResult
can be used for multiple purposes like sending a message or responding to a websocket
request.handleRequest
with GraphQLServerRequest
: Use as alternative webserver middleware or if custom actions should be
done before sending back a response. Create an instance of GraphQLServer
and use the request provided by the
webserver as parameter for this function. You might need request values,
see Webserver compatibility. The returned GraphQLExecutionResult
can be used to execute
custom logic with the result and/or prepare or send a response.handleRequest
with GraphQLRequestInfo
and GraphQLServerResponse
: Use if a GraphQLRequestInfo
is available and
a response should be sent from this request.You can create a new instance of GraphQLServer
with the options necessary for your tasks. The
handleRequest
function of the GraphQLServer
can be integrated with many fitting webservers.
Note regarding POST requests:
graphql-server version 3 and higher try to extract the request information from the request.body
field. Some webserver
frameworks like Express might need a fitting body parser in order to populate this body
field.
string/text
(recommended): graphql-server will handle reading content and parsing it to JSON.object/JSON
: graphql-server will read JSON and try to assign it to matching fields. This might cause
FetchErrors if the body contains invalid JSON. We recommend using text parsers instead so graphql-server can respond
with a fitting GraphQL error response if JSON is invalid.1const graphQLServerPort = 3592 2const graphQLServerExpress = express() 3const customGraphQLServer = new GraphQLServer({ schema: someExampleSchema }) 4graphQLServerExpress.use(bodyParser.text({ type: '*/*' })) 5graphQLServerExpress.all('/graphql', (req, res) => { 6 return customGraphQLServer.handleRequest(req, res) 7}) 8graphQLServerExpress.listen({ port: graphQLServerPort }) 9console.info(`Starting GraphQL server on port ${graphQLServerPort}`)
GraphQLServer
provides default values and behaviour out of the box. It is recommended to at least provide a schema
so the request won't be rejected because of a missing/invalid schema. When using it with a local schema it is
recommended to provide a rootValue
to return a fitting value. Examples for these requests can be found in the
integration test in the GraphQLServer.integration.test.ts
class in the tests/server
folder.
Validation rules can be used to define how the GraphQLServer
should behave when validating the request against the
given schema. To ease the use GraphQLServer
uses the specifiedRules
from graphql-js library. If you don't want
to use the default validation rules you can overwrite them by setting defaultValidationRules
option to []
.
Warning!
Setting both defaultValidationRules
and customValidationRules
options to []
will disable validation. This might
result in unexpected responses that are hard to use for API users or frontends.
1import { NoSchemaIntrospectionCustomRule } from 'graphql' 2 3const graphQLServerPort = 3592 4const graphQLServerExpress = express() 5const customGraphQLServer = new GraphQLServer({ 6 schema: someExampleSchema, 7 defaultValidationRules: [], 8}) 9graphQLServerExpress.use(bodyParser.text({ type: '*/*' })) 10graphQLServerExpress.all('/graphql', (req, res) => { 11 return customGraphQLServer.handleRequest(req, res) 12}) 13graphQLServerExpress.listen({ port: graphQLServerPort }) 14console.info(`Starting GraphQL server on port ${graphQLServerPort}`)
If you want to define custom validation rules you can use the customValidationRules
option (e.g. to handle
introspection like shown in the example below).
Introspection can be used to get information about the available schema. While this may be useful in development environments and public APIs you should consider disabling it for production if e.g. your API is only used with a specific matching frontend.
Introspection can be disabled by adding the NoSchemaIntrospectionCustomRule
from the graphql-js library to the
customValidationRules
option.
1import { NoSchemaIntrospectionCustomRule } from 'graphql' 2 3const graphQLServerPort = 3592 4const graphQLServerExpress = express() 5const customGraphQLServer = new GraphQLServer({ 6 schema: someExampleSchema, 7 customValidationRules: [NoSchemaIntrospectionCustomRule], 8}) 9graphQLServerExpress.use(bodyParser.text({ type: '*/*' })) 10graphQLServerExpress.all('/graphql', (req, res) => { 11 return customGraphQLServer.handleRequest(req, res) 12}) 13graphQLServerExpress.listen({ port: graphQLServerPort }) 14console.info(`Starting GraphQL server on port ${graphQLServerPort}`)
Hot reload of the GraphQL schema can be used to update the existing schema to a new version without restarting the GraphQL server, webserver or whole application. When setting a new schema it will be used for the next incoming request while the old schema will be used for requests that are being processed at the moment. Hot reloading is especially useful for remote schemas that are processed in another application like a webservice.
The schema can be changed simply by calling setSchema
in the GraphQLServer
instance. In the example below a second
route is used to trigger a schema update.
1const graphQLServerPort = 3592 2const graphQLServerExpress = express() 3const customGraphQLServer = new GraphQLServer({ schema: someExampleSchema }) 4graphQLServerExpress.use(bodyParser.text({ type: '*/*' })) 5graphQLServerExpress.all('/graphql', (req, res) => { 6 return customGraphQLServer.handleRequest(req, res) 7}) 8graphQLServerExpress.all('/updateme', (req, res) => { 9 const updatedSchema = someMagicHappened() 10 customGraphQLServer.setSchema(updatedSchema) 11 return res.status(200).send() 12}) 13graphQLServerExpress.listen({ port: graphQLServerPort }) 14console.info(`Starting GraphQL server on port ${graphQLServerPort}`)
There are 2 builtin MetricsClient
implementations available.
MetricsClient
. Provides GraphQLServer related metrics without but does not provide NodeJS metrics like cpu and memory usage.The SimpleMetricsClient provides three custom metrics for the GraphQL server:
A simple metrics endpoint can be created by using getMetricsContentType
and getMetrics
functions from
the GraphQLServer
instance. In the example below a second route is used to return metrics data.
1const graphQLServerPort = 3592 2const graphQLServerExpress = express() 3const customGraphQLServer = new GraphQLServer({ schema: someExampleSchema }) 4graphQLServerExpress.use(bodyParser.text({ type: '*/*' })) 5graphQLServerExpress.all('/graphql', (req, res) => { 6 return customGraphQLServer.handleRequest(req, res) 7}) 8graphQLServerExpress.get('/metrics', async (req, res) => { 9 return res 10 .contentType(customGraphQLServer.getMetricsContentType()) 11 .send(await customGraphQLServer.getMetrics()) 12}) 13graphQLServerExpress.listen({ port: graphQLServerPort }) 14console.info(`Starting GraphQL server on port ${graphQLServerPort}`)
The GraphQLServer
does not handle CORS requests on its own. It is recommended to handle this on the webserver level,
e.g. by using cors
library with an Express webserver like in the example below.
1const graphQLServerPort = 3592 2const graphQLServerExpress = express() 3graphQLServerExpress.use(cors()) 4const customGraphQLServer = new GraphQLServer({ schema: someExampleSchema }) 5graphQLServerExpress.use(bodyParser.text({ type: '*/*' })) 6graphQLServerExpress.all('/graphql', (req, res) => { 7 return customGraphQLServer.handleRequest(req, res) 8}) 9graphQLServerExpress.listen({ port: graphQLServerPort }) 10console.info(`Starting GraphQL server on port ${graphQLServerPort}`)
The handleRequest
function works with webservers that provide a fitting request and
response object that matches GraphQLServerRequest
and GraphQLServerResponse
interface. As Express (since
version 2.x) matches both no further adjustment is necessary. If one or both objects do not match GraphQLServerRequest
and GraphQLServerResponse
it might still be possible to map the webserver request and response objects to these interfaces.
In the following table a list of webserver frameworks/versions can be found that are able to run GraphQLServer
.
The Version
column shows the version of the webserver framework we tested GraphQLServer
version 4 with.
If the request and/or response has to be mapped it is noted in the Mapping
column. There is a code
examples on how to use handleRequest
without providing a GraphQLServerResponse
and sending the response with the
functionality provided by the webserver.
Framework/Module | Version | Mapping | Example |
---|---|---|---|
AdonisJS | 6.3 | request, response | AdonisJS example |
Express | > = 2.x | none | Express example |
fastify | 4.23 | response | Fastify example |
hapi | 21.3.7 | request, no response | hapi example |
Koa | 2.15.2 | response | Koa example |
Next.js | 14.1.4 | none | Next.js example |
Nitro | 4.9.5 | request | Nitro example |
NodeJS http | 20.x | request | NodeJS http example |
Socket.IO | 4.7.5 | response | Socket.IO example |
gRPC | 1.8.14 | no response | gRPC example |
Deno | 1.42.1 | request, no response | Deno HTTP example |
Bun | 1.1.0 | request, no response | Bun example |
GraphQLServerRequest
and GraphQLServerResponse
interfaces
The GraphQLServerRequest
and GraphQLServerResponse
are available in the @dreamit/graphql-server-base module.
This allows extensions such as custom Logger
or MetricsClient
implementations to implement these interfaces without
defining @dreamit/graphql-server
as dependency.
1export interface GraphQLServerRequest { 2 headers: IncomingHttpHeaders 3 url?: string 4 body?: unknown 5 method?: string 6} 7 8export interface GraphQLServerResponse { 9 statusCode: number 10 setHeader( 11 name: string, 12 value: number | string | ReadonlyArray<string>, 13 ): this 14 end(chunk: unknown, callback?: () => void): this 15 removeHeader(name: string): void 16}
GraphQLServer
, like many GraphQL libraries, uses a context function to create a context object that is available
during the whole request execution process. This can for example be used to inject information about request headers
or adjust responses. An example can be found in the CustomSendResponse.integration.test.ts
class in the test/server folder.
1export interface GraphQLServerOptions { 2 readonly contextFunction?: (contextParameters: { 3 serverOptions: GraphQLServerOptions 4 request?: GraphQLServerRequest 5 response?: GraphQLServerResponse 6 }) => unknown 7}
The GraphQLServer
accepts the following options. Note that all options are optional and can be overwritten by calling
the setOptions
function of the GraphQLServer
instance.
schema
: The schema that is used to handle the request and send a response. If undefined the GraphQLServer
will
reject responses with a GraphQL error response with status code 500.shouldUpdateSchemaFunction
: Function that can be used to determine whether a schema update should be executed.formatErrorFunction
: Function that can be used to format occurring GraphQL errors. Given a GraphQLError
it
should return a GraphQLFormattedError
. By default defaultFormatErrorFunction
is called that uses error.toJSON
to
format the error.schemaValidationFunction
: Function that is called when a schema is set or updated. Given a GraphQLSchema
it
can return a ReadonlyArray<GraphQLError>
or an empty array if no errors occurred/should be returned. By
default validateSchema
from graphql-js library is called.parseFunction
: Function that is called to create a DocumentNode
with the extracted query in the request
information. Given a source
and ParseOptions
it should return a DocumentNode
. By default parse
from graphql-js library is called.defaultValidationRules
: Default validation rules that are used when validateSchemaFunction
is called.
Both defaultValidationRules
and customValidationRules
will be merged together when validateSchemaFunction
is called. By default specifiedRules
from graphql-js are used. Can be overwritten if no or other default rules
should be used.customValidationRules
: Custom validation rules that are used when validateSchemaFunction
is called.
Both defaultValidationRules
and customValidationRules
will be merged together when validateSchemaFunction
is called. By default, an empty array is set. Can be overwritten to add additional rules
like NoSchemaIntrospectionCustomRule
.validationTypeInfo
: Validation type info that is used when validateSchemaFunction
is called.validationOptions
: Validation options containing { maxErrors?: number }
that is used
when validateSchemaFunction
is called.removeValidationRecommendations
: If true
removes validation recommendations like "users not found. Did you
mean user?". For non-production environments it is usually safe to allow recommendations. For production environments
when not providing access to third-party users it is considered good practice to remove these recommendations so users
can not circumvent disabled introspection request by using recommendations to explore the schema.validateFunction
: Validation function that validates the extracted request against the available schema. By
default validate
from graphql-js library is called.rootValue
: Root value that is used when executeFunction
is called. Can be used to define resolvers that handle
how defined queries and/or mutations should be resolved (e.g. fetch object from database and return entity).fieldResolver
: Field resolver function that is used when executeFunction
is called. Default is undefined, if
custom logic is necessary it can be added.typeResolver
: Type resolver function that is used when executeFunction
is called. Default is undefined, if
custom logic is necessary it can be added.executeFunction
: Execute function that executes the parsed DocumentNode
(created in parseFunction
) using
given schema, values and resolvers. Returns a Promise or value of an ExecutionResult
. By default execute
from graphql-js library is called.extensionFunction
: Extension function that can be used to add additional information to the extensions
field
of the response. Given a GraphQLRequestInfo
, ExecutionResult
, GraphQLServerOptions
and context it should return undefined or an ObjMap
of key-value-pairs that are added to theextensions
field. By default defaultExtensions
is used and returns undefined.reassignAggregateError
: If true
and the ExecutionResult
created by the executeFunction
contains
an AggregateError
(e.g. an error containing a comma-separated list of errors in the message and an originalError
containing multiple
errors)
this function will reassign the originalError.errors
to the ExecutionResult.errors
field. This is helpful if
another application creates AggregateErrors
while the initiator of the request (e.g. a Frontend app) does not expect
or know how to handle AggregateErrors
.contextFunction
: Given GraphQLServerOptions
, GraphQLServerRequest
and GraphQLServerResponse
this function is used to create a context value that is available in the whole request flow.
Default implementation is defaultContextFunction
that returns the given GraphQLServerRequest
.
Can be used to extract information from the request and/or response and return them as context.
This is often used to extract headers like 'Authorization' and set them in the execute function.executionResultErrorMessage:
: Error message that is used in logging if a response contains an errors
element.fetchErrorMessage:
: If provided and not set to undefined, used as fixed error message if a FetchError occurs.graphqlExecutionErrorMessage:
: Error message that is used in logging if an error is thrown when execute
function is called.validationErrorMessage:
: Error message that is used in logging if one or more errors occurred when calling the validate
function.methodNotAllowedResponse:
: Function given a method as string
returns an error that the used method is not allowed by GraphQLServer
.invalidSchemaResponse:
: Default error that is returned with set schema is invalid.missingQueryParameterResponse:
: Default error that is returned if no query is available in the GraphQLRequestInfo
.onlyQueryInGetRequestsResponse:
: Function given an operation as string
returns an error that the used operation is not allowed for GET
requests.collectErrorMetricsFunction:
: Given an error name as string, error as unknown
, GraphQLServerOptions
and context as unknown
this function
can be used to trigger collecting error metrics. Default implementation is defaultCollectErrorMetrics
that increase
the error counter for the given errorName or Error by 1.logger
: Logger to be used in the GraphQL server. TextLogger
and JsonLogger
as well as NoStacktraceTextLogger
and NoStacktraceJsonLogger
(useful for tests without the need for a stacktrace) and NoLogger
(useful if no logging should be done but logger is required) are available in the module. Own
Logger can be created by implementing Logger
interface.extractInformationFromRequest
: Function that can be used to extract information from the GraphQLServerRequest
and return a Promise<GraphQLRequestInfo>
. By default, the extractInformationFromRequest
function is used that tries to
extract the information from the body (using request.body
field) and URL params of the request.sendResponse
: Function used to send a fitting response being either a data
or error
response.
By default, the sendResponse
is used that tries to create and send a response using the functions provided
by the given GraphQLServerResponse
.metricsClient
: The MetricsClient
used to collect metrics from the GraphQLServer. By default,
the SimpleMetricsClient
is used that collects three custom metrics. Own MetricsClient can be used by implementing MetricsClient
interface.responseEndChunkFunction
: Function used to adjust the chunk/body before it is used in the response.end
function call in the sendResponse
function. By default it stringifies the ExecutionResult and creates a Buffer from this string.adjustGraphQLExecutionResult
: Function used to adjust the GraphQLExecutionResult
before it is returned.To make it easier to customize and extend the GraphQLServer
classes and class functions are public. This makes extending
a class and overwriting logic easy.
In the example below the logic of TextLogger
is changed to add the text "SECRETAPP" in front of every log output.
1export class SecretApplicationTextLogger extends TextLogger { 2 prepareLogOutput(logEntry: LogEntry): string { 3 return `SECRETAPP - ${super.prepareLogOutput(logEntry)}` 4 } 5}
If you have questions or issues please visit our Issue page and open a new issue if there are no fitting issues for your topic yet.
graphql-server is under MIT-License.
No vulnerabilities found.
Reason
no binaries found in the repo
Reason
13 out of 13 merged PRs checked by a CI test -- score normalized to 10
Reason
no dangerous workflow patterns detected
Reason
update tool detected
Details
Reason
project is fuzzed
Details
Reason
license file detected
Details
Reason
30 commit(s) and 5 issue activity found in the last 90 days -- score normalized to 10
Reason
all dependencies are pinned
Details
Reason
SAST tool is run on all commits
Details
Reason
GitHub workflow tokens follow principle of least privilege
Details
Reason
0 existing vulnerabilities detected
Reason
branch protection is not maximal on development and all release branches
Details
Reason
project has 1 contributing companies or organizations -- score normalized to 3
Details
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
Found 0/3 approved changesets -- score normalized to 0
Reason
security policy file not detected
Details
Score
Last Scanned on 2024-12-17T17:37:19Z
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More