Skip to content

Instantly share code, notes, and snippets.

@sramam
Last active October 5, 2021 04:21
Show Gist options
  • Save sramam/5773e3a3a60a788ad070f8da2248c6c3 to your computer and use it in GitHub Desktop.
Save sramam/5773e3a3a60a788ad070f8da2248c6c3 to your computer and use it in GitHub Desktop.
noun-and-verb.md

A workable abstract model of an API server

  • Built with Prisma, Apollo Server, GraphQL and a sprinking of ✨ pixie dust ✨
  • This document is a barebones description of the product in the making.

This is the high level idea of what a GraphQL server looks like.

             ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐              
                       Backend                        
┏━━━━━━━━┓   ├──────┐          ┌───────┤    ┏━━━━━━━━┓
┃database┃◀━▶│Prisma│◀────────▶│GraphQL│◀━━▶┃ client ┃
┗━━━━━━━━┛   ├──────┘          └───────┤    ┗━━━━━━━━┛
             └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ - ┘

The Prisma-GraphQL link requires quite a bit of wiring to get working. Prisma is an ORM, allowing code to access the DB, hiding most of the SQL complexity. schema.prisma is a way to specify the database shape - tables and fields.

GraphQL is a API schema definition mechanism. It is defined by schema.graphql The schema.graphql consists of two parts: data-specification (objects + fields) and operations ("Queries"/"Mutations"). The operations can have a pre-defined set based on CRUD methods (that's create/read/update/delete) and other custom methods that are defined by the domain.

This is very tedious and mostly duplicative to the schema.prisma.

Further, once schema.graphql is defined, it's important to define the code that implements its "operations" - which graphQL calls "resolvers". These are just functions that the graphQL server calls at the appropriate time with the appropriate arguments. Predictably, this mirrors the specification in schema.graphql and involves some boiler plate and hooking things up.

So the picture grows to something like below:

             ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐              
                       Backend                        
┏━━━━━━━━┓   ├──────┐          ┌───────┤    ┏━━━━━━━━┓
┃database┃◀━▶│Prisma│─────────▶│GraphQL│◀━━▶┃ client ┃
┗━━━━━━━━┛   ├──────┘          └───────┤    ┗━━━━━━━━┛
                    ┌─────────┐    │                  
             │      │resolvers│◀───┘   │              
              ─ ─ ─ ┴─────────┴ ─ ─ ─ ─               

The product/tool does these fundamental things:

  • Adds some "doc annotations" (the @readonly kinda tags, but in the documentation) to prisma.schema
  • Execute npx prisma generate, which generates:
    • a prisma client (TypeScript for now, but the core engine is in Rust - other languages are in the works)
    • types.schema.graphql Create/Update/Delete/Read/Search GraphQL types
    • crud.schema.graphql Resolvers for CRUD Api interfaces defined by Prisma
    • Typescript resolvers to bind to the prisma client
    • There is a working CRUD API generated at this point
  • User adds domain specific "verbs" to custom.schema.graphql
  • GraphQL best practice is to define domain specific verbs. User can optionally ignore crud.schema.graphql
  • Re-running prisma generate now generates stub resolvers/functions for the operations defined in custom.schema.graphql
  • Developer implements custom resolver functions and the API server is good to go.

For the moment, we'll use graphql-codegen to generate client SDK and GraphQL clients.

A more detailed architectural view then looks like below:

{1}
┌ ─ ─ ─ ─ ─ ┐
   Prisma           GraphQL generator┌───────────────┐
│data-model │─[2]───┬───────────────▶│ GraphQL(base) │
 ─ ─ ─ ─ ─ ─        │                ├───────────────┤
                    │             {3} GraphQL(domain) ─[4]─┐
             prisma client           └ ─ ─ ─ ─ ─ ─ ─ ┘  │  │
                    │                                   │  │
                    ▼                                   │  │
             ┌────────────┐           GraphQL codegen   │  │
             │Prisma Types│        ┌─────(server)───────┘  │
┏━━━━━━━━┓   ├────────────┤        │                       │
┃database┃◀━▶│ Prisma API │        │                GraphQL codegen
┗━━━━━━━━┛   └────────────┘        ▼                   (client)
                    ▲  ┌──────────────────────┐            │
                    │  │  GraphQL Data Types  │            ▼
                    │  ├──────────────────────┤   ┌────────────────┐   ┏━━━━━━┓
                    └──│GraphQL Resolver Types│◀──│ GraphQL Client │◀━▶┃client┃
                       ├──────────────────────┘   └────────────────┘   ┗━━━━━━┛
                    {5} GraphQL Resolver Code │
                       └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─

There are other tools that do things that are similar, but nothing comes close to this level of automation, flexibility and simplicity.

To reiterate, outside the doc-annotations on the prisma schema and a generator block in schema.prisma no new abstractions and/or code was added. Prisma/GraphQL/ApolloServer/TypeScript are all best-in-class solutions to building modern services. The offer excellent performance, developer ergonomics, vibrant open-source communities, velocity of progress and talent pools.

Hiring new talent is both much easier and of a higher caliber. It's also possible to excite sleeping tigers within the organization. A win-win on all fronts.

--

Roadmap

Short term (single digit weeks)

Studio

Once this core capability works, a "studio" app will provide visualization of both the schemas. Initially, they'll be independent, but eventually, they'll be cross linked, even to a VS code instance. So you could build/inspect/debug/fix your application completely in the browser in a fraction of the time it'd normally take.

In-App Studio

To take things a step further, these tools cam be made available as React components which can be embedded inside the client application - in dev mode. So one application will contain both the rendered customer view and the developer interface to make changes. The context switch required to move between views, setting up dev environments, onboarding devs are all essentially tending to zero with such an approach.

Medium term (2-4 months)

Transformation of legacy services

Once the studio app is in place, it's relatively simple to ingest an existing (prisma supported) database schema, and provide automated tools to partition this algorithmically into smaller micro-services based on the data-base connectivity patterns. The algorithmic first approximations will be human editable to fit the domains semantic needs. The product can then generate fully functional micro-services from a monolith. 10's if not 100's of man years can be reduce to a button click.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment