Daniele Irsuti - Frontend developer

Prisma, non un ORM tradizionale

Premessa: questo diventerà un articolo complementare alla serie di GraphQL, in quanto strettamente collegato ad esso.

Difficile dire cos’è Prisma, forse riesce meglio dire cosa non è. Non è un ORM tradizionale, non crea dei modelli (o entità) nel linguaggio in cui stiamo sviluppando, ma crea degli schema in una strana estensione .prisma.

Il flusso

Sulla documentazione ufficale di Prisma c’è la stessa immagine che riporto sotto per dare un’idea ad altissimo livello su come lavora Prisma dietro le quinte.

alt

Prisma si interfaccia con il database come segue:

  • Connettendosi al DB, innanzitutto;
  • Introspeziona lo schema del DB e genera il datamodel (che sarà proprio datamodel.prisma, il file prodotto di cui ne ho già accennato)
  • Genera il client, un codice autogenerato che può essere integrato nel nostro software nel linguaggio che scegliamo, lo spiego meglio più avanti.

Creare un’applicazione Prisma

Nota: Per la mia applicazione d’esempio, ho utilizzato un database mongo che avevo su una virtual machine. Faccio questa doverosa precisazione perché l’introspezione su mongodb alla data in cui scrivo non è supportata e questo presenta un ostacolo se l’architettura di partenza è pensata database-first, perché sarete costretti a creare tutti gli schema manualmente. Sorry.

Per utilizzare Prisma a pieno occurrono alcuni passaggi preliminari:

  • Bisogna avere installato sulla propria macchina Docker (e ahimè non si scappa);
  • Installare la CLI di Prisma:

    npm install -g prisma

o per mac:

 brew tap prisma/prisma
 brew install prisma

Adesso ti servirà il microservizio di Prisma, contenuto in un container docker per agganciarci al nostro database e generare lo schema. Per farlo, ci metteremo sulla directory scelta del progetto e creeremo il file docker-compose.yml, che ho già opportunamente modificato per farlo funzionare con il mio db:

version: '3'
services:
  prisma:
    image: prismagraphql/prisma:1.28
    restart: always
    ports:
    - "4468:4468"
    environment:
      PRISMA_CONFIG: |
        port: 4468
        databases:
          default:
            connector: mongo
            uri: mongodb://172.22.156.180
            database: "test"
  mongo:
    image: mongo:3.6
    restart: always
    environment:
      MONGO_INITDB_ROOT_USERNAME: prisma
      MONGO_INITDB_ROOT_PASSWORD: prisma
    ports:
      - "27017:27017"
    volumes:
      - mongo:/var/lib/mongo
volumes:
  mongo:

La mia prima impressione è stata:

Pura. Magia. Nera.

Tentando di semplificare mi sono concentrato su:

  • Connection string del database
  • Porta che utilizzerà il servizio

Una volta impostate entrambe, Prisma introspezionerà il db e genererà lo schema, ma solo eseguendo il seguente comando:

 docker-compose up -d

Se l’esito del comando dato sarà positivo, vedrai che si è generato un file denominato datamodel.prisma che conterrà quanto segue come default:

type User {
  id: ID! @unique
  name: String!
}

Bene, hai il tuo schema generato ma nonostante ciò non puoi ancora interagire con il db. Per farlo ci serve che prisma generi per noi un servizio che ci permetta di interrogare il db e fare delle operazioni. Per questo, creeremo un secondo file ma stavolta generandolo tramite questo comando:

prisma init --endpoint http://localhost:4468

Questo genererà un file prisma.yml che in questa introduzione userai per generare il client e inizializzare il servizio.

Il file prisma.yml si presenterà così al suo interno:

endpoint: http://localhost:4468
datamodel: datamodel.prisma

A questo aggiungi le due proprietà con i relativi sotto elementi, il perché lo spiego a seguire:

endpoint: http://localhost:4468
datamodel: datamodel.prisma
databaseType: document
generate:
  - generator: javascript-client
    output: ./generated/prisma-client/

NOTE: Da documentazione ufficiale, se il db è Mongo deve essere esplicitata la proprietà databaseType a document. Prisma su questo fronte mi da’ l’impressione di essere ancora un po’ acerbo per mongo ma sono sicuro che subirà ancora aggiornamenti non lontani dalla data in cui scrivo questo post.

La proprietà generate esplicita in quale linguaggio il codice per generare il client, deve essere prodotto. Dal momento che mi trovo su node ho ovviamente optato per il javascript-generator e impostato come output ./generated/prisma-client/, ma tu vai e sii l’artefice del tuo destino.

Fatto ciò, esegui il comando che genererà, come da te indicato, il codice:

prisma generate

Se adesso tu andassi a dare un’occhiata al file nel percorso ./generated/prisma-client/schema-prisma.js troveresti qualcosa di familiare… il datamodel.prisma riscritto come proprietà typeDefs!

module.exports = {
        typeDefs: // Code generated by Prisma ([email protected]). DO NOT EDIT.
  // Please don't change this file manually but run `prisma generate` to update it.
  // For more information, please read the docs: https://www.prisma.io/docs/prisma-client/
  
  //... omesso il resto per brevità
}

Tornando alla directory principale, installa le dipendenze per far funzionare il codice staticamente prodotto:

 npm init -y
 npm install --save prisma-client-lib

Crea il file index.js e scrivi una funzione che crei un utente:

const { prisma } = require('./generated/prisma-client')

// A `main` function so that we can use async/await
async function main() {

  // Create a new user called `Alice`
  const newUser = await prisma.createUser({ name: 'Alice' })
  console.log(`Created new user: ${newUser.name} (ID: ${newUser.id})`)

  // Read all users from the database and print them to the console
  const allUsers = await prisma.users()
  console.log(allUsers)
}

main().catch(e => console.error(e))

Finito! Adesso mettiamo su il servizio…

Fatto questo, possiamo dare il finale ed agognato comando:

prisma deploy

Quest’ultimo avvierà un servizio che ti permetterà di interagire con il db con lo schema graphQL. In console vedrai un messaggio come questo:

Deploying service `default` to stage `default` to server `local` 566ms

L’endpoint che puoi consultare sarà lo stesso che avete dichiarato all’inizio, ossia http://localhost:4468

Se a questo punto tu dessi il comando:

node index

Verrà:

  • generato un utente di nome “Alice”
  • ritornata una lista di tutti gli utenti

Esplorando il servizio con il playground offerto da yoga (l’editor visuale online per eseguire le query in graphql) hai a disposizione tutta la documentazione necessaria per fare mutation, query e subscription.

Se utilizzi quel codice staticamente prodotto e decidi di aggiornare il datamodel.prisma ricordati che devi far rigenererare al tuo client, per farlo ridai sempre il comando:

prisma generate

Link utili

Prisma docs (Sito ufficiale)