- 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 typescrud.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 incustom.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.
--
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.
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.
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.