maticzav / graphql-middleware Goto Github PK
View Code? Open in Web Editor NEWSplit up your GraphQL resolvers in middleware functions
License: MIT License
Split up your GraphQL resolvers in middleware functions
License: MIT License
Hey, thanks for a great library!
I was wondering if it's possible to blacklist instead of whitelisting queries/mutations? I.e. this is how we do it today:
export const authMiddleware = {
Query: {
getUsers: isAuthenticated,
}
}
Where isAuthenticated
is applied for the getUsers
query. However, now I need to add every single query in here or do the following:
export const authMiddleware = {
Query: isAuthenticated,
}
which applies it to all queries. However, I want some queries to be able to get without being authenticated. It would be nice if you could do something like:
export const authMiddleware = {
Query: isAuthenticated,
except: ['getPublicProfile', 'getBlogPost']
}
Or is this possible in any way at the moment?
As explain here : dotansimha/graphql-yoga#314 documentMiddleware
is not yet available. What do you think of removing it from README.md and only document middleware
parameter of Graphql-Yoga ?
hi all, i am using nextjs, api routes, and nexus. trying to implement the middleware like below. its working on query, but not mutation. what could be the possible reason?
const middleware = {
Query: {
findManyProduct: async (resolve, parent, args, context, info) => {
console.log('this gets called')
const result = await resolve(parent, args, context, info)
return result
}
},
Mutation: {
// createOneCompany: slugCounter,
createOneProduct: async (resolve, parent, args, context, info) => {
console.log('this doesnt')
const result = await resolve(parent, args, context, info)
return result
}}
import * as types from './graphql'
import { paljs } from '@paljs/nexus'
import { join } from 'path'
import { applyMiddleware } from 'graphql-middleware'
import permissions from './middleware/permissions'
import slugCounter from './middleware/slugCounter'
export const schema = applyMiddleware(
makeSchema({
types,
// plugins: [paljs({ includeAdmin: true })],
plugins: [paljs()],
outputs: {
schema: join(process.cwd(), 'src', 'generated', 'schema.graphql'),
typegen: join(process.cwd(), 'src', 'generated', 'nexus-typegen.ts'),
},
typegenAutoConfig: {
sources: [
{
source: '@prisma/client',
alias: 'prisma',
},
{
source: require.resolve('./context'),
alias: 'Context',
},
],
contextType: 'Context.Context',
},
}),
slugCounter,
permissions,
)
Hi! Thanks for this project! 😸
Sorry if it looks like a silly question, but I can't figure out how can I send an error to frontend from the middleware. I tried to implement something like this:
const midAuth = async (resolve, root, args, context, info) => {
if (!context.auth)
return {
error: 'wrong token',
};
const result = await resolve(root, args, context, info);
return result;
};
(or just throw an error)
but it doesn't work as I expected
Is there a way to apply the middleware just for some data sources?
I have multiple data sources and not all of them need to use my middlewares for its resolvers.
Does it make sense at all ?
Thanks
hi all, i use express + passport-oauth2 in my web.
and i want to use graphql to wrap exist restapi, with permission check.
i follow the examples/permissions , but in this line
the context.request.isAuthenticated()
alway false,
and i debug into the code, it looks like the this
have nothing about auth info.
anybody can tell me how to use this library whit passport ?
Hello,
It seems that there is an incompatibility issue between graphql-middleware and apollo-server@^2.2.0
Here you can find an explanation about what is breaking : apollographql/apollo-server#1935 (comment)
So apparently something in graphql-middleware is turning the introspection query execution (from graphql/execution
into a Promise instead of returning an object.
Another related issue : apollographql/apollo-server#1934
In the meantime, the last working version is [email protected]
Would like to apply multiple middlewares to a schema in an easier:
e.g.
compose(
applyFieldMiddleware(metricsMiddleware, authMiddleware, beepMiddleware),
applyDocumentMiddleware(responseSizeMiddleware)
)(schema)
Using this library for permission management.
But there is some misleading info in path when validation of type
failed.
Example.
Schema:
type Query {
user(id: Int!): User
}
type User {
id: Int!
email: String!
username: String!
}
Apply middleware on User
type:
schema = applyMiddleware(schema, {
User: () => new ForbiddenError(`Access denied`)
})
then following query (that return User
type)
{
user(id: 1) {
username
email
}
}
throwing error:
{
"errors": [
{
"message": "Access denied",
"locations": [
{
"line": 3,
"column": 5
}
],
"path": [
"user",
"username"
],
"extensions": {
"code": "FORBIDDEN"
}
}
],
"data": {
"user": null
}
}
Look at locations
and path
- it includes first queried attribute of User
(username
). Which is misleading.
Ideally it should show information regarding user
query only:
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"user"
]
Basically following middlewares currently return same path
and location
in error when they shouldn't:
[
{
User: () => new ForbiddenError(`Access denied`)
},
{
User: {
username: () => new ForbiddenError(`Access denied`)
}
}
]
The cause is where addResolveFunctionsToSchema
from graphql-tools
is used which is actually updating the schema rather than replacing it, causing continues re-wrap of middleware on resolver when it is called and this in turn makes queries against the schema slower and slower.
showcase: https://github.com/gdeividas/graphql-middleware
for demonstration run:
yarn
npx tsc && npx ava dist/test/showcase.test.js
When using grapql middleware with graphql shield permissions
There is an error with this repository's Renovate configuration that needs to be fixed. As a precaution, Renovate will stop PRs until it is resolved.
Error type: undefined. Note: this is a nested preset so please contact the preset author if you are unable to fix it yourself.
node_modules/graphql-middleware/dist/types.d.ts:40:18 - error TS2430: Interface 'IResolverOptions<TSource, TContext>' incorrectly extends interface 'GraphQLField<any, any, any>'.
Types of property 'resolve' are incompatible.
Type 'IFieldResolver<TSource, TContext> | undefined' is not assignable to type 'GraphQLFieldResolver<any, any, any> | undefined'.
Type 'IFieldResolver<TSource, TContext>' is not assignable to type 'GraphQLFieldResolver<any, any, any>'.
Types of parameters 'info' and 'info' are incompatible.
Type 'GraphQLResolveInfo' is not assignable to type 'GraphQLResolveInfo & { mergeInfo: MergeInfo; }'.
Type 'GraphQLResolveInfo' is not assignable to type '{ mergeInfo: MergeInfo; }'.
Property 'mergeInfo' is missing in type 'GraphQLResolveInfo'.
40 export interface IResolverOptions<TSource = any, TContext = any> extends GraphQLField<any, any, any>
Let me first thank you for this great lib!
I came across a use case where I would like to use a middleware to change the parent argument of a resolver:
const typeDefs = `
type Query {
hello(name: String): String
}
`
const myMiddleware = {
Query: {
hello: (resolve, parent, args, context, info) => {
const newParent = { foo: 'bar' };
return resolve(newParent);
},
},
}
But in my resolver the parent is always null... Any reason why we do not allow modifying the parent object for a root query?
Thanks!
I have a problem with Sentry. It complains about missing sources when stack with graphql-middleware
is reached.
node_modules/graphql-middleware/dist/index.js
there is a reference to //# sourceMappingURL=index.js.map
which is ok since node_modules/graphql-middleware/dist/index.js.map
does exist in the npm package.node_modules/graphql-middleware/dist/index.js.map
there is reference to "sources":["../src/index.ts"]
which is not shipped with the package.Currently, my workaround is to manually pull git repository to get these .ts
file and upload it to sentry.
I am not sure what is the best practice here, i.e. should src/index.ts
be shipped with npm package?
I believe that would make sense since you are already shipping .map
file but that would increase package size.
master
branch failed. 🚨I recommend you give this issue a high priority, so other packages depending on you could benefit from your bug fixes and new features.
You can find below the list of errors reported by semantic-release. Each one of them has to be resolved in order to automatically publish your package. I’m sure you can resolve this 💪.
Errors are usually caused by a misconfiguration or an authentication problem. With each error reported below you will find explanation and guidance to help you to resolve it.
Once all the errors are resolved, semantic-release will release your package the next time you push a commit to the master
branch. You can also manually restart the failed CI job that runs semantic-release.
If you are not sure how to resolve this, here is some links that can help you:
If those don’t help, or if this issue is reporting something you think isn’t right, you can always ask the humans behind semantic-release.
The npm token configured in the NPM_TOKEN
environment variable must be a valid token allowing to publish to the registry https://registry.npmjs.org/
.
If you are using Two-Factor Authentication, make configure the auth-only
level is supported. semantic-release cannot publish with the default auth-and-writes
level.
Please make sure to set the NPM_TOKEN
environment variable in your CI with the exact value of the npm token.
Good luck with your project ✨
Your semantic-release bot 📦🚀
For example there are 30 resolvers and we know that 27 of them need auth middleware and only 3 of them don't. The way that I know about from the docs is to specify all the 27 resolvers that require the middleware. Is there a way to do the opposite, i.e. write only the 3 resolvers to be excluded for the auth middleware?
Hi, I'm trying to add multiple middlewares to a resolver function (for authorization purposes)
the problem is that when I try to do that like this :
const middlewares = [bodyParser, passport.authenticate('jwt', { session : false })];
const schemaWithMiddleware = applyMiddleware(schema, middlewares);
I get this error :
/graphql-middleware/dist/validation.js:24
throw new MiddlewareError("Type " + type + " exists in middleware but is missing in Schema.");
Error: Type 0 exists in middleware but is missing in Schema.
I'm seeing a noticeable performance hit when using graphql-middleware. I was hoping to use middleware to log resolver errors. Before going all in, I added a very simple middleware and deployed to production to test under load:
export const errorLogger = async (resolve, root, args, context, info) => {
try {
return await resolve(root, args, context, info);
} catch (err) {
// TODO: log errors
throw err;
}
};
Instrumentation showed time spent in Node doubled and overall response time was 10-15% slower.
The server is apollo-server-express. I've previously added schema directives to add some instrumentation to resolvers and saw no performances hit with those.
I really like the idea of graphql-middleware for something like logging/error reporting but the extra overhead. Any ideas on how to optimize?
The instructions for graphql-middleware
are pretty straightforward — but they only seem to apply to schema-first development if I’m not mistaken.
I’ve now implemented nexus-prisma, but since this approach is code-first, the resolvers, when called, haven’t yet compiled into the actual resolvers (if that makes sense?), so I’m receiving the following error message:
.../node_modules/graphql-yoga/node_modules/graphql-middleware/dist/validation.js:1
Error: Field Query.name exists in middleware but is missing in Schema.
at .../node_modules/graphql-yoga/node_modules/graphql-middleware/dist/validation.js:17:27
at Array.forEach (<anonymous>)
at .../node_modules/graphql-yoga/node_modules/graphql-middleware/dist/validation.js:15:43
at Array.forEach (<anonymous>)
at Object.validateMiddleware (.../node_modules/graphql-yoga/node_modules/graphql-middleware/dist/validation.js:9:29)
at addMiddlewareToSchema (.../node_modules/graphql-yoga/node_modules/graphql-middleware/dist/middleware.js:19:42)
at normalisedMiddlewares.reduceRight.schema.schema (.../node_modules/graphql-yoga/node_modules/graphql-middleware/dist/middleware.js:52:87)
at Array.reduceRight (<anonymous>)
at applyMiddlewareWithOptions (.../node_modules/graphql-yoga/node_modules/graphql-middleware/dist/middleware.js:51:79)
at applyMiddleware (.../node_modules/graphql-yoga/node_modules/graphql-middleware/dist/middleware.js:78:12)
// Packages
import { GraphQLServer } from 'graphql-yoga'
import { nexusPrismaPlugin } from 'nexus-prisma'
import { makeSchema } from 'nexus'
// Types
import types from './types'
// Middleware
import systemLogCreate from './resolvers/mutations/systemLogCreate'
import systemLogErrorCreate from './resolvers/mutations/systemLogErrorCreate'
new GraphQLServer({
schema: makeSchema({
types: { ...types, ...resolvers },
plugins: [nexusPrismaPlugin()]
}),
middlewares: [
systemLogCreate,
systemLogErrorCreate
]
// Packages
import { mutationType } from 'nexus'
// Components
import systemLogCreate from './System/SystemLog/systemLogCreate'
import systemLogErrorCreate from './System/SystemLog/systemLogErrorCreate'
export default {
Mutation: mutationType({
definition(t) {
t.field('systemLogCreate', {
type: 'SystemLog',
resolve: systemLogCreate
})
t.field('systemLogErrorCreate', {
type: 'SystemLogError',
resolve: systemLogErrorCreate
})
}
})
}
export default async (resolve, root, args, ctx, info) => {
// First resolve all resolvers...
try {
return await resolve(root, args, ctx, info)
} catch (err) {
// ...and if an error occurs in any of them, log it and tie it to session.
const sessionId = args.sessionId
delete args.sessionId
const error = ctx.photon.systemLogErrors.create({
data: {
args,
error: err
}
})
// Throw it to communicate it to browser.
throw new Error(err)
}
}
I'm calling setMessage
trying to return id
from the created message. But if there's an error I get the following message:
Cannot return null for non-nullable field Message.id.
The only way to avoid this is to change from ID!
to ID
. Is there anything I can do to get the actual error instead of this?
Request:
POST http://localhost:4000/graphql
Content-Type: application/json
X-REQUEST-TYPE: GraphQL
mutation setMessage {
setMessage(input: { message: "a@@gmail.com"}) {
error
message
id
}
}
resolver
import * as yup from 'yup'
export const messageMutations = {
setMessage: {
validationSchema: yup.object().shape({
input: yup.object().shape({ message: yup.string().email() }),
}),
resolve(_, { input }) {
return { id: (Math.random() * 100) | 0, message: input.message }
},
},
}
In prisma/photon TS example graphql-auth a comment references non-working graphql-shield in issue #361
The problem appears when graphql-middleware 3.0.2 is installed as a dependency of graphql-yoga.
Resolving graphql-middleware to 3.0.1 eliminates the error and graphql-shield works as expected.
Only works with yarn
, npm install
does not process resolutions
"resolutions": {
"graphql-middleware": "3.0.1"
}
$ ts-node-dev --no-notify --respawn --transpileOnly ./src
Using ts-node version 8.3.0, typescript version 3.5.3
TypeError: definitions.trim is not a function
at parseFragmentToInlineFragment (/Users/glen/Documents/JavaScript/Research/hello-photon-graphql-auth/node_modules/graphql-middleware/src/fragments.ts:85:21)
at /Users/glen/Documents/JavaScript/Research/hello-photon-graphql-auth/node_modules/graphql-middleware/src/fragments.ts:41:24
at Array.map (<anonymous>)
at Object.extractFragmentReplacements (/Users/glen/Documents/JavaScript/Research/hello-photon-graphql-auth/node_modules/graphql-middleware/src/fragments.ts:40:6)
at addMiddlewareToSchema (/Users/glen/Documents/JavaScript/Research/hello-photon-graphql-auth/node_modules/graphql-middleware/src/middleware.ts:40:32)
at normalisedMiddlewares.reduceRight.schema (/Users/glen/Documents/JavaScript/Research/hello-photon-graphql-auth/node_modules/graphql-middleware/src/middleware.ts:86:13)
at Array.reduceRight (<anonymous>)
at applyMiddlewareWithOptions (/Users/glen/Documents/JavaScript/Research/hello-photon-graphql-auth/node_modules/graphql-middleware/src/middleware.ts:78:77)
at applyMiddleware (/Users/glen/Documents/JavaScript/Research/hello-photon-graphql-auth/node_modules/graphql-middleware/src/middleware.ts:129:36)
at new GraphQLServer (/Users/glen/Documents/JavaScript/Research/hello-photon-graphql-auth/node_modules/graphql-yoga/src/index.ts:137:13)
[ERROR] 18:09:25 TypeError: definitions.trim is not a function
Hey all, trying to figure out if I'm approaching this wrong or just not understanding. So, what I'd like to do is put a simple tracing middleware around any "top level" query. I.e. the request comes in and they ask for PersonA
and PersonB
query.
I've got one that runs, and I can filter out decently well by only measuring if parent
is null, which seems to work. But the downside is that it's making my introspection query SUPER slow – proabbly because it's hitting every prop and we have a huuuge schema which is split into multiple files and stitched together. Also, we're on lambda, so we recompile this on every invocation (at least locally) so our dev cycles are suffering.
I'm wondering: is there some easy way to say wrap Query.* and Mutation.*
but not anything deeper? I saw #13 and looked at the applyMiddlewareToDeclaredResolvers
but it doesn't seem to have much impact.
Thoughts? Am I missing something simple?
graphql-middleware
is currently modifying the passed schema and returning it, rather than functionally returning new clean copy of schema.
The resolve
argument can be an object with resolve
field.
Nevermind, I think I'm missing some coffee. 😄
When tried to use multiple middle-wares with a query it failed with the errors below.
/Users/user/Desktop/example/node_modules/graphql-middleware/dist/validation.js:20
throw new MiddlewareError(`Expected ${type}.${field} to be a function but found ` +
^
MiddlewareError: Expected Query.secured to be a function but found object
at /Users/user/Desktop/example/node_modules/graphql-middleware/dist/validation.js:20:27
at Array.forEach (<anonymous>)
at /Users/user/Desktop/example/node_modules/graphql-middleware/dist/validation.js:15:43
at Array.forEach (<anonymous>)
at Object.validateMiddleware (/Users/user/Desktop/example/node_modules/graphql-middleware/dist/validation.js:9:29)
at addMiddlewareToSchema (/Users/user/Desktop/example/node_modules/graphql-middleware/dist/middleware.js:19:42)
at normalisedMiddlewares.reduceRight.schema.schema (/Users/user/Desktop/example/node_modules/graphql-middleware/dist/middleware.js:52:87)
at Array.reduceRight (<anonymous>)
at applyMiddlewareWithOptions (/Users/user/Desktop/example/node_modules/graphql-middleware/dist/middleware.js:51:79)
at applyMiddleware (/Users/user/Desktop/example/node_modules/graphql-middleware/dist/middleware.js:78:12)
const {
GraphQLServer
} = require('graphql-yoga')
const typeDefs = `
type Query {
open: String!
secured: String!
me: Me!
}
type Me {
name: String!
surname: String!
age: Int!
}
`
const code = 'supersecret'
const isLoggedIn = async (resolve, parent, args, ctx, info) => {
// Include your agent code as Authorization: <token> header.
const permit = ctx.request.get('Authorization') === code
if (!permit) {
throw new Error(`Not authorised!`)
}
return resolve()
}
+ const log = async (resolve, parent, args, ctx, info) => {
+ console.log('Aqwertyuiop');
+ return resolve()
+ }
const resolvers = {
Query: {
open: () => `Open data, everyone's welcome!`,
secured: () => `Personal diary - this is for my eyes only!`,
me: () => ({}),
},
Me: {
name: () => 'Ben',
surname: () => 'Cool',
age: () => 18,
},
}
// Middleware - Permissions
const permissions = {
Query: {
+ secured: [log, isLoggedIn],
- secured: isLoggedIn,
},
Me: isLoggedIn,
}
// Server
const server = new GraphQLServer({
typeDefs,
resolvers,
context: req => ({
...req
}),
middlewares: [permissions],
})
server.start(() => console.log('Server is running on http://localhost:4000'))
Is there any support for multiple middle-wares?
There can be an utility function or in-build support for multiple middleware.
Hi there,
Thanks for all of the hard work on this library.
I just battled a bug for a while, it was very confusing trying to figure out what was happening. The answer it seems is that applyMiddleware
is actually mutating the schema passed into it. I was under the assumption that the API was immutable, considering the modified schema is returned from applyMiddleware
. This assumption led me to believe that I could reuse the schema passed in without the middleware applied. This caused big problems.
It would be nice if applyMiddleware
could be immutable as the API implies. Is there a reason for it to not be immutable?
If mutations are necessary for some reason, could this be documented somewhere?
Thanks!
I've been able to successfully apply middleware for fields, but when I try to apply one to a type resolver, it only applies the middleware to that type's field resolvers, not the type resolver itself.
Is there a way to only have it apply to the type resolver?
For example, given the below resolvers, I'd like to wrap the Contact
type resolver, but I can only seem to get it to apply to that type's fields (e.g, name
below).
// RESOLVERS
{
// mock type resolver
Contact: () => {
return {
name: () => { /* field resolver */ }
}
},
Query: () => {
contacts: () => { /* field resolver */ }
}
}
// MIDDLEWARE
applyMiddleware(schema, {
Contact: myMiddleware()
})
I see that graphql-middleware intentionally doesn't run on introspection queries. This makes sense, but I have a use case where it's causing problems.
I am trying to manage database transactions at the middleware and context level. I create the transaction in the context factory (because I have dataloaders created in context that I want to provide the transaction to). The middleware then handles committing or rolling back the transaction based on whether the query was successful.
This works great except for the introspection query, because that query triggers context creation but not the middleware, resulting in transactions that are opened but never committed. I could fix this by creating and committing the transactions entirely in the middleware, but as I mentioned before I need the transaction available when creating the context.
So yeah, being able to opt in to this somehow would be helpful.
I have found graphql-middleware
to be very helpful when building https://github.com/lifeomic/graphql-resolvers-xray-tracing . Thank you for sharing it.
In that same project, I'd like to wrap only non-default resolvers and I thought others might want that same behavior. If you would accept it, I'd be happy to create a PR that adds a an option to the applyMiddleware
function. Should I work on a PR that adds that feature?
Hello !
I have the following resolvers, (schema created with makeExecutableSchema
)
const resolvers = {
Muation: {
viewerMutation: (_, args, context) => {
book: () => {
author: ({id}) => getAuthorForBook(id)
}
},
},
}
And I am trying to do something like this:
const logMiddleware = {
Muation: {
viewerMutation: async (resolve, parent, args, context, info) => {
book: () => {
author: ({id}) => {
console.log('request author for book:', id)
return resolve(root, {id}, context, info)
}
}
},
},
}
But I am getting an issue, the resolve
inside author
is not calling getAuthorForBook
.
I would have expected to find a resolver
argument on author
but nested types seem to behave differently from root types (under Mutation or Query)
Is this a normal behavior ?
Before publishing our timeout middleware to npm, I figured I’d ask if you had a specific naming scheme in mind for middleware? I settled on graphqlTimeoutMiddleware
for now: artsy/metaphysics#1068
Thanks for this library btw!
Hi!
I’d love to use this library, but there’s no license specified. Would you mind committing one?
Thanks!
So I think this might just be an limitation of working with schema stitching, but in case things aren't working as intended:
I have a remote database which accepts graphql queries. There is a Person type like so
type Person {
id: ID!
primaryEmailAddresses: [EmailAddress!]!
primaryEmailAddress(ownerId: ID!): EmailAddress
}
type Query {
person(id: ID!): Person
}
I've stitched the database's schema to the another "main" schema running in ApolloServer. The main schema shows the public:
type Person {
id: ID!
primaryEmailAddress: EmailAddress
}
type Query {
person(id: ID, emailAddress: String): Person
}
I have a middleware function (associated with the "main" schema) which gets the "ownerId" from the context
, and automatically adds it as an argument to the Person.primaryEmailAddress
resolver.
{
Person: {
primaryEmailAddress: async(resolve: Function, parent, args, context, info) => {
if (!context.user) return null;
const newArgs = args
? { ...args, ownerId: context.user.perspective }
: { ownerId: context.user.perspective };
return await resolve(parent, newArgs, context, info)
}
}
}
Additionally, I have a custom resolver function associated with Query.person
which delegates the response to the database schema. This means that Query.person
gets delegated to the database schema before person.primaryEmailAddress
is called.
Unfortunately, I'm finding that, after the main schema delegates the response to the database schema, the Person.primaryEmailAddress
middleware is not triggered.
Hello, thanks for the package!
I am trying to setup logging with middleware. It would be nice to be able to log name of actual resolver function like so:
const loggingMiddleware = async (
resolve,
root,
args,
context,
info
) => {
console.log(`${resolve.name} args:`, args)
const result = await resolve(root, args, context, info)
console.log(`${resolve.name} result:`, result)
return result
}
and I expect it to log: "getUser args: {} ".
I think it would be required for resolvers to be an actual function and not anonymous, but I am ok with it as long as I can map log entry to the resolver file.
Hi
Now when the middleware has a field which is not declared in the schema, an error will be thrown as below:
TypeError: Cannot read property 'resolve' of undefined
at applyMiddlewareToField (.../node_modules/graphql-middleware/src/index.ts:61:24)
at .../node_modules/graphql-middleware/src/index.ts:93:18
at Array.reduce (<anonymous>)
at applyMiddlewareToType (.../node_modules/graphql-middleware/src/index.ts:90:47)
at .../node_modules/graphql-middleware/src/index.ts:138:17
at Array.reduce (<anonymous>)
at generateResolverFromSchemaAndMiddleware (.../node_modules/graphql-middleware/src/index.ts:135:47)
at addMiddlewareToSchema (.../node_modules/graphql-middleware/src/index.ts:156:21)
at .../node_modules/graphql-middleware/src/index.ts:171:7
at Array.reduce (<anonymous>)
at applyMiddleware (.../node_modules/graphql-middleware/src/index.ts:169:43)
at Object.<anonymous> (.../src/schema/index.js:13:16)
at Module._compile (internal/modules/cjs/loader.js:678:30)
at loader (.../node_modules/babel-register/lib/node.js:144:5)
at Object.require.extensions.(anonymous function) [as .js] (.../node_modules/babel-register/lib/node.js:154:7)
at Module.load (internal/modules/cjs/loader.js:589:32)
at tryModuleLoad (internal/modules/cjs/loader.js:528:12)
at Function.Module._load (internal/modules/cjs/loader.js:520:3)
at Module.require (internal/modules/cjs/loader.js:626:17)
at require (internal/modules/cjs/helpers.js:20:18)
at Object.<anonymous> (.../src/app/app.js:6:1)
at Module._compile (internal/modules/cjs/loader.js:678:30)
Is there any way that I can extract the __typename of a resolver response in my middleware?
Hello,
let's say we have the following book type:
type Book { title: String author: String pagecount: Int cover: Cover }
A problem I've noticed in this implementation is that if a middleware is specific to a field (the Book query in our case), then this middleware will be executed 5 times. First time in the Book query resolver, then 4 more times for every field resolver in the Book type.
Is there any way how I can limit the middleware to only be executed once (for the Book query resolver only)? Or did I miss someting?
graphql-js 15 is out. When installing this module, a peer dependency warning is issued when using graphql 15.
I know I have to be misunderstanding something, but I can get middlewares to work if I apply them directly, but not if I scope them to a certain part of the tree. Everything in the docs and issues makes me thing at least two of these logs should print on every query, but only #3 prints:
schema = applyMiddleware(
schema,
{
Query: (resolve, root, args, context, info) => {
console.log('1>>>>')
return resolve(root, args, context, info)
},
Mutation: (resolve, root, args, context, info) => {
console.log('2>>>>')
return resolve(root, args, context, info)
}
},
(resolve, root, args, context, info) => {
console.log('3>>>>')
return resolve(root, args, context, info)
}
)
Any idea what I'm missing?
Unless I've missed something, I don't think it's supported:
It would be great to handle wildcard middlewares as in graphql-shield.
Hi everyone, first I want to thank you for this great library, I have used it with Apollo server, all worked great intend of repeatedly calling, it's calling middleware for each field returned from a handler, and args
argument is empty
export const authMiddleware = async (resolve, root, args, ctx: Context, info) => {
const mutationField = info.schema.getMutationType();
const mutationDefinition = mutationField.getFields()[info.fieldName];
if (mutationDefinition && mutationDefinition.auth) {
try {
const token = ctx.headers['authorization'].replace('Bearer ', '');
const data = await Crypto.decodeJwt<{ id: string }>(token);
const user = await User.findOne(data.id);
ctx.state.auth = {
user,
data,
token
};
} catch (e) {
throw new AuthenticationError('unauthorized');
}
}
const data = await resolve(root, args, ctx, info);
console.log(data);
return data;
};
Rather than fragment replacements...
Currently applyMiddlewareToField
only spreads the properties it wants to:
It would be really useful if extra properties were also added to the final field definition, that way we could declare some custom properties that could be used directly in the middlewares.
For instance, we could have a middleware added to all mutations, but that only does something to mutations that have a specific flag.
// ...
const resolvers = {
// ...
Mutation: {
// ...
DoSomething: {
flags: [FLAGS.SPECIFIC_FLAG],
resolve: async (root, args, context, info)=> {
// ...
},
}
},
}
then on the middleware:
const customValidation = {
async Mutation(resolve, root, args, context, info) {
// use info to get the _typeConfig of the mutation being executed
const mutationConfig = ...;
if (mutationConfig.flags && mutationConfig.flags.includes(FLAGS.SPECIFIC_FLAG)) {
// Do something
}
}
}
I'm asking for that because I'm migrating some code that uses graphql-add-middleware to use graphql-middleware
instead.
I'm going to write a post about validations with graphql-middleware
, but for it to work I need this "feature".
Thoughts?
I can get some time to work on that if it's acceptable.
addResolveFunctionsToSchema
from graphql-tools
does spreads all other properties, so it's not a problem.
See related code there:
https://github.com/apollographql/graphql-tools/blob/3b77c2071e4b2328b1a4c4471c61d4ad93a6ae57/src/generate/addResolveFunctionsToSchema.ts#L121
As the title suggests this issue is used to find a great logo for graphql-middleware
.
The best idea I got so far, which would also somehow reflect the name, is a group or three cartoon animals with the middle one wearing a GraphQL T-Shirt - something like npm’s wombat.
I would love to hear all the ideas you’ve come up with! 😄
On top of this issue maticzav/graphql-shield#416 we faced noticeable performance degradation when graphql-shield
applied. After few stages of investigation it turned out that there is a small bug in graphql-middleware
itself, where for applyMiddlewareToDeclaredResolvers
it will apply to declared resolver only for first middleware in sequence here, and all fields will be affected for next middlewares, due to presence of field, and passing of this condition
README.md
currently says
- Easiest way to handle GraphQL middleware: Intuitive, yet familiar API will get under your skin in a second.
"To get under someone's skin" means to annoy someone (dictionary.com reference). It would take a very remarkable API to accomplish this in just one second. :-)
Consider alternative phrasing like
An intuitive, yet familiar API that you will pick up in a second.
I'm not sure if I'm missing something but as far as I can tell, the only way to apply multiple middlewares to a specific resolver is to do the following as per this article
const middleware1 = {
Query: {
hello: logInput,
bye: logInput,
},
}
const middleware2 = {
Query: {
bye: logResult,
},
}
const middlewares = [middleware1, middleware2]
Wouldn't it be better to do it this way instead? I feel like the above method would get out of hand pretty fast.
const loggingMiddleware = {
Query: {
hello: logInput,
bye: {logInput, logResult} //OR [logInput, logResult]
},
}
const middlewares = [loggingMiddleware]
I tried to check if this was possible but I got the following error:
Error: Expected Query.hello to be a function but found object
I don't mean to complain or anything but I also feel like the documentation needs to be a little better. It's incomplete and a bit unclear.
Thanks!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.