Comments (6)
I looked through Nexus' plugin, most of them should not need extensions. Just plain, reuse-able higher order functions.
Take your authentication for example, we just create a function that takes a regular resolver, and return a new resolver, and can be used on any field that requires auth
const adminOnly = (resolver) => (parent, args, ctx) => {
if (Permissions.isAdmin(ctx.currentUser)) return resolver(ctx, parent, args);
return null // or return error
}
fields: [
t.field('allUsers', {
type: ListOfUsers,
resolver: adminOnly(() => { return Users.getAll() })
})
]
The same pattern can be applied to pretty everything on that plugin list.
For the relay ID example. You create a new GraphQL RelayId Scalar type, which is used for parsing and serializing a leaf node. Roughly
const globalId = t.scalarType('globalId', {
serialize: toGlobalId,
parse: fromGlobalId
})
fields: [
t.defaultField("id", globalId)
]
from gqtx.
Could be a great idea - any rough example what would the API look like?
from gqtx.
A quick sketch:
type VisibilityExtension = {
visibilityAccess?: "public" | "hidden";
}
type LiveQueryExtensions = {
liveQuery?: {
buildResourceIdentifier: (source: unknown) => string;
},
}
type TExtensions = VisibilityExtension & LiveQueryExtensions
const t = createTypesFactory<TContext, TExtensions>();
const Character = t.objectType({
name: "Character",
extensions: {
visibilityAccess: "public"
},
fields: () => [
t.field("name", {
type: t.NonNull(t.String),
resolve: (character) => "HI",
}),
],
});
Note extensions are just there for adding metadata to the schema. Actually doing sth with the metadata must be done in user-land. We could however provide some way of at least providing typings for the available extensions.
I guess we will hit limits on what we can do. E.g. buildResourceIdentifier
would receive the source
object of the object type (in the user-land implementation), however, I am not aware of how that could be typed properly in a general way.
from gqtx.
I created #36 for a basic implementation. It does however not use any typing magic, but I guess stuff like that could still be introduced later on.
from gqtx.
I was asked for some examples of use cases, here are some.
interface TExtensions {
authorize?: (ctx: TContext) => boolean;
authenticate?: boolean;
}
const t = createTypesFactory<TContext, TExtensions>({
extensions: {
authorize: { // first arg is whatever value passed to authorize, in this case a fn
extendObjectTypeResolver: (checkAuth) => async (parent, args, ctx, info) => {
const isAuthorized = await checkAuth(ctx);
if (!isAuthorized) throw new AuthorizationError()
}
},
authenticate: {
extendObjectTypeResolver: (needsAuthentication) => async (parent, args, ctx, info) => {
const isAuthenticated = await ctx.checkDbForSession(ctx.user.id);
if (!isAuthenticated) throw new AuthenticationError()
}
},
}
});
const Mutation = t.mutationType({
fields: [
t.field('doStuffOnlyAdminShouldDo', {
type: SomeResponseType,
args: {
id: t.arg(t.NonNullInput(t.ID)),
},
extensions: {
authorize: (ctx) => ctx.checkRoles(['ADMIN']),
authenticate: true,
},
resolve: (_, args, ctx) => {
...
},
}),
],
});
Now for a more complicated example, and probably much harder to define with TS
import { fromGlobalId } from 'graphql-relay';
const t = createTypesFactory<TContext, TExtensions>({
extensions: {
parse: {
extendInputType: (parseFn) => async (args, argName) => {
// mutates the args object before the resolver runs
// parse function will also validate inputs and throw if invalid
args[argName] = await parseFn(args[argName]);
},
},
},
});
const MyInputType = t.inputObjectType<{ id: string }>({
name: 'MyInputType',
extensions: {
// arg should have the same type as input
parse: async (input) => {
// input.id is a Relay Global Object Identifier, it needs to be parsed into the id that is actually used in the db
return {
realId: fromGlobalId(input.id),
};
},
},
fields: () => [t.defaultField('id', t.ID)],
});
const Mutation = t.mutationType({
fields: [
t.field('doStuffOnlyAdminShouldDo', {
type: SomeResponseType,
args: {
input: t.arg(t.NonNullInput(MyInputType)),
},
// type of `args.input` is now the return type of its parse extension
// { realId: string }
resolve: (_, args, ctx) => {},
}),
],
});
I expect it wouldnt be feasible, but a simpler version where you only validate the input and throw an exception if its bad (without mutating args) might be.
There is a lot of inspiration to be taken from nexus's plugins https://nexusjs.org/docs/api/plugins
from gqtx.
yea, thats a totally fair decision. These are quality of life features only that could make the complexity explode
from gqtx.
Related Issues (20)
- `relay.js` missing from last beta release HOT 6
- Nullability of fields returning object types HOT 1
- Please provide an ESM build HOT 2
- non required field arguments are improperly typed HOT 1
- Self referencing objectType has type any HOT 2
- README example is broken HOT 2
- canary release does not include transpiled js code HOT 3
- Mutation `fields` signature HOT 1
- proposal: use changesets for versioning
- Add implicit field resolution without the need of `defaultField` HOT 2
- Lazy fields declaration HOT 1
- unify t.objectType, t.mutationType and t.subscriptionType
- Nullable input type HOT 10
- Docs update needed.
- package not published properly (v0.8.0) HOT 1
- Return the root query type
- Allow interface to contain implementation HOT 1
- Support for graphql 16 HOT 7
- Resolve function is necessary when a built-in scalar can be undefined HOT 8
- Comparison of gqtx vs. Nexus vs. Pothos (giraphql)? HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from gqtx.