I wrote a post talking about actual pros and cons of using GraphQL in a post before
This was primarily for people just walking around social media throwing it around like they did for typescript.
Just installing a new tool doesn't solve problems! , it might mitigate it a bit but it doesn't solve the inherent problem of you not using it properly.
I could go on this rant, or I can talk about the actual topic.
As always, I was stalking github repositories for learning stuff and github explore actually kept showing repo's from the-guild.dev and since I'd already gone through most of their tools I kept skipping but then I didn't find anything interesting so I did end up at their site again.
Apparently, I did miss a library. It's named GraphQL Yoga and this is one of the few libraries that is functionally minimalistic.
Stuff that it has covered for you
I've never hated graphql, it's fun, handles most of the boilerplate code but then I wouldn't say it's a all out solution to all problems that you face with REST.
and I've talked about this in the previous post about GraphQL, so you can read that there. The same goes for typescript, I use it where it would be a better choice, more about this in a future post.
This section is more about how the DSL can actually be quite easy to use and allows you to iterate faster.
so here's what a simple ping query would look like in the graphql dsl
type Query{
ping: String
}
and that's it, you have a graphql schema done.
Yeah, we aren't kids, we know how the DSL works Then why not use it!?
Moving forward. The next this is to get the DSL executable so it could link to programmatic resolvers.
This can be done in all graphql server libraries out there, instead of buildSchema you can just pass in the schema file to the server creation instance.
I'm going to go through doing this with Yoga cause it's my blog.
import { createServer } from '@graphql-yoga/node'
const server = createServer({
schema: {
typeDefs: `
type Query {
ping: String
}
`,
resolvers: {
Query: {
ping: () => 'pong',
},
},
},
})
server.start()
That would take about 30-45 seconds to write and so graphql ping in 30 seconds (a facepalm for the younger me who said it couldn't be possible.)
The example is pretty much self explanatory but let's see how we can extend this.
A very basic use case is going to be authentication and passing around
context
.
This isn't very different from other graphql server implementations but here's the additions you'd do
import { createServer } from "@graphql-yoga/node";
+ import { useGenericAuth } from '@envelop/generic-auth';
const server = createServer({
schema: {
typeDefs: `
type Query {
- ping: String
+ ping: String @skipAuth
+ privatePing: String @auth
}
`,
resolvers: {
Query: {
ping: () => "pong",
+ privatePing: () => "another pong",
},
},
+ plugins:[useGenericAuth({
+ resolveUserFn,
+ validateUser,
+ mode: 'protect-granular',
+ })]
},
});
server.start();
and now you have granular control over what needs authentication and what doesn't.
You can also use graphql-shield to add authorization controls but I'd prefer writing my own as helpers and use them in the resolver since more often than not I do need the resolved data to find if the requestor should have access to it.
overall more time spent writing logic than getting the tooling working, which is what we've been trying to do all this time , right?
But, but but!
You obviously saw this coming.
.graphql
file that you can read through to find the
types.schema.gql
file. This would be just 1-2 files when working with
something like type-graphql since you'd already have most of the stuff
autocompleted for you.Though, in my opinion these can be easily made a little more easier by adding typescript just for autocompleting the function definitions.
That's about it for this post. Adios!