Iterative GraphQL

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

  1. Setting up a graphql server
  2. Works with envelop.dev plugins by default
  3. DSL first - which, most of them are and most people just prefer the
    graphql-js approach (type-graphql or graphql pothos) which adds the
    modularisation of code easier but still complicated cause the same could be
    written in the DSL in one line (anyway, personal preference so can't
    complain.)

You actually like a graphql library now?

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.

GraphQL Yoga

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.

Auth

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.

Why is this iterative?

  1. Reduced time to get typescript decorators to get working. (type reflection
    isn't always perfect)
  2. It's now just a function invocation so I can add more composable stuff than
    having to depend on the structure of a library (ex: class types from
    type-graphql)

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!

It's not all amazing

You obviously saw this coming.

  1. You still need to define input and output types which are rather easy to do
    since it's all in one .graphql file that you can read through to find the
    types.
  2. The context switch is a little more but manageable. You move between 2-3
    files at any given point to write a resolver, import it , and define it in
    the 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!