MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Distribuisci un'API GraphQL con MongoDB Atlas e Apollo Server su Koyeb

Introduzione

Negli ultimi anni, nuovi framework, librerie e linguaggi si sono fatti strada sulla scena tecnologica e hanno lottato per ottenere l'adozione mainstream, ma un recente pezzo di tecnologia che ha visto un'enorme adozione da parte dei team di ingegneri del software in un breve periodo è GraphQL. Rilasciato da Facebook nel 2015, è stato implementato in più linguaggi di programmazione e ha portato alla creazione di diversi framework e librerie relative a GraphQL.

GraphQL è un linguaggio di query fortemente tipizzato per le API e un runtime per soddisfare le query con i dati esistenti. Consente ai client di eseguire query per molte risorse in un'unica richiesta richiedendo i campi obbligatori invece di effettuare richieste a più endpoint.

Apollo Server è un server GraphQL open source che fornisce un modo semplice per creare un'API GraphQL in grado di utilizzare dati provenienti da più origini, inclusi diversi database e persino API REST.

MongoDB Atlas è una piattaforma dati applicativa completamente gestita che gestisce la creazione, la gestione e la distribuzione di MongoDB nel cloud. Fornisce una facile distribuzione dei database MongoDB a vari provider di servizi cloud con diversi strumenti per la gestione dei database MongoDB in un ambiente di produzione.

In questo tutorial impareremo come creare e distribuire un server GraphQL connesso a un'origine dati MongoDB. Alla fine di questo tutorial, avrai creato un'API GraphQL funzionale utilizzando Apollo Server e MongoDB Atlas e l'avrai distribuita alla produzione su Koyeb.

Requisiti

Per seguire con successo questo tutorial, hai bisogno di quanto segue:

  • Una macchina di sviluppo con Node.js installato. L'app demo in questo tutorial utilizza la versione 16.14.0 di Node.js
  • Una macchina di sviluppo con Git installato
  • Un account Atlas MongoDB
  • Un account Koyeb per distribuire l'applicazione

Passaggi

I passaggi per creare un'API GraphQL con Apollo DataSource e MongoDB Atlas e distribuirla alla produzione su Koyeb includono:

  1. Crea un database MongoDB utilizzando MongoDB Atlas
  2. Imposta il progetto
  3. Crea un server GraphQL utilizzando Apollo Server
  4. Collega il server GraphQL al database MongoDB
  5. Utilizza MongoDB come origine dati GraphQL
  6. Distribuisci su Koyeb

Crea un database MongoDB utilizzando Mongo Atlas

MongoDB Atlas offre la possibilità di creare database MongoDB distribuiti nel Cloud con pochi clic e, in questa sezione, creerai un database MongoDB utilizzando MongoDB Atlas.

Dopo aver effettuato l'accesso al tuo account Atlas MongoDB, fai clic sul pulsante "Crea un database" nella pagina "Distribuzioni dati" ed esegui i seguenti passaggi:

  • Fai clic sul pulsante "Crea" sul tipo di distribuzione preferito.
  • Seleziona un provider Cloud e una regione preferiti o utilizza le opzioni preselezionate.
  • Inserisci un nome cluster o utilizza il nome cluster predefinito.
  • Fai clic sul pulsante "Crea cluster".
  • Seleziona l'opzione di autenticazione "Nome utente e password", inserisci un nome utente e una password e fai clic sul "pulsante Crea utente". Conserva il nome utente e la password in un luogo sicuro per un uso successivo.
  • Inserisci "0.0.0.0/0" senza virgolette nel campo Indirizzo IP della sezione Elenco di accesso IP e fai clic sul pulsante "Aggiungi voce".
  • Fai clic sul pulsante "Termina e chiudi" e poi sul pulsante "Vai ai database". Verrai reindirizzato alla pagina "Data Deployments", con il tuo nuovo cluster MongoDB ora visibile.
  • Fai clic sul pulsante "Connetti" accanto al nome del tuo cluster MongoDB, seleziona l'opzione "Connetti la tua applicazione" e copia la stringa di connessione al database in un luogo sicuro per un uso successivo.

Seguendo i passaggi precedenti, hai creato un database MongoDB per leggere e archiviare i dati per l'API GraphQL. Nella sezione successiva, configurerai il progetto e installerai le librerie e le dipendenze necessarie.

Configura il progetto

In questa sezione, imposterai un progetto npm e installerai le dipendenze necessarie per creare il server GraphQL demo per questo tutorial. Il server GraphQL esporrà un'API GraphQL che legge e scrive i dati dei filmati da e verso il database MongoDB creato nella sezione precedente. Inizia creando una directory principale per il progetto sulla tua macchina di sviluppo. Per farlo, esegui il comando seguente nella finestra del tuo terminale:

mkdir graphql_movies

I graphql_movies la directory creata dal comando sopra è la directory principale per l'applicazione demo. Quindi, passa a graphql_movies directory e inizializzare un repository Git nella directory eseguendo il comando seguente nella finestra del terminale:

cd graphql_movies
git init

Il primo comando sopra ti porta nel graphql_movies directory nel tuo terminale, mentre il secondo comando inizializza un repository Git per tenere traccia delle modifiche nel graphql_movies directory. Quindi, crea un progetto npm in graphql_movies directory eseguendo il comando seguente nella finestra del terminale:

npm init --yes

Esecuzione di npm init il comando inizializza un progetto npm vuoto e crea un package.json file nella directory principale. Il --yes flag risponde automaticamente "sì" a tutti i prompt generati da npm.

Con un progetto npm ora attivo, vai avanti e installa le librerie e i pacchetti necessari per creare l'API GraphQL. Nella finestra del tuo terminale, esegui i comandi seguenti:

npm install apollo-server graphql mongoose apollo-datasource-mongodb dotenv rimraf

npm install -D @babel/preset-env @babel/core @babel/node @babel/cli

L'npm install il comando sopra installa 10 pacchetti nel progetto e li aggiunge al package.json del progetto file. Il primo comando installa le dipendenze necessarie per eseguire l'app, mentre il secondo installa le dipendenze necessarie durante lo sviluppo dell'app. Le dipendenze installate includono:

  • apollo-server:una libreria open source per la creazione di server GraphQL.
  • graphql:l'implementazione JavaScript della specifica GraphQL.
  • mongoose:un mappatore di documenti oggetto per MongoDB.
  • apollo-datasource-mongodb:una libreria di origini dati Apollo per MongoDB.
  • dotenv:una libreria per la gestione delle variabili d'ambiente.
  • rimraf:una libreria per l'esecuzione di UNIX rm -rf comando in Node.js.

Le altre librerie installate per lo sviluppo includono una serie di babel librerie per eseguire e trasferire codice JavaScript moderno.

Quindi, crea un .babelrc file nella directory principale del progetto e aggiungere il codice seguente al file:

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "useBuiltIns": "usage",
        "corejs": "3.0.0"
      }
    ]
  ]
}

Il codice sopra indica a Babel come transpilare l'ultimo codice JavaScript presente nell'app utilizzando env di Babel opzioni di configurazione.

Infine, crea un src cartella nella directory principale del progetto. Questo src cartella conterrà tutti i file di progetto. Con queste modifiche, la struttura del progetto è a posto e, nella sezione successiva, creerai un server GraphQL utilizzando la libreria Apollo Server.

Crea un server GraphQL utilizzando Apollo Server

In questa sezione creerai un server GraphQL utilizzando Apollo Server. La libreria Apollo Server viene fornita con un server Express integrato e può eseguire query e mutazioni GraphQL. Fornisce inoltre una sandbox interna al browser per la connessione a un server GraphQL, la scrittura e l'esecuzione di query GraphQL, la visualizzazione dei risultati delle query e l'esplorazione dello schema GraphQL del server.

Un server GraphQL è costituito da uno schema GraphQL che definisce la struttura della sua API e da risolutori che implementano la struttura dello schema. Uno schema GraphQL è costituito da types , che descrive i dati che possono essere interrogati e restituiti dal server GraphQL. GraphQL fornisce un linguaggio di definizione dello schema (SDL) utilizzato per definire uno schema GraphQL. Utilizzando l'SDL di GraphQL, un tipo di film può essere definito come segue:

type Movie {
  _id: ID!
  title: String!
  rating: Float!
  year: Int!
  }

Il Movie tipo sopra definisce i quattro campi che possono essere interrogati su un film e il loro tipo restituito. GraphQL ha anche tre tipi di radice; query , mutation e subscription . Questi tre tipi servono come punti di ingresso a un server GraphQL e definiscono le possibili operazioni eseguibili in un server GraphQL. La query type è per le operazioni di recupero dati, la mutation type è per le operazioni di creazione o modifica dei dati e l'subscription type è per operazioni di recupero dati in tempo reale.

Per creare uno schema per il server GraphQL, crea un typeDefs.js file nel src cartella e aggiungere il seguente codice al file:

import { gql } from 'apollo-server';

export const typeDefs = gql`
  type Movie {
    _id: ID!
    title: String!
    rating: Float!
    year: Int!
  }

  type Query {
    getMovies: [Movie!]!,
    getMovie(id: ID!): Movie!
  }

  type Mutation {
    createMovie(title: String!, rating: Float!, year: Int!): Movie!
  }
`;

Il codice sopra è una definizione del tipo di schema GraphQL e definisce tre tipi GraphQL; Movie , Query e Mutation . La Query e Mutation tipi sono i tipi radice, mentre il Movie la mutazione definisce i campi interrogabili per i record di film.
La Query digitare nella definizione dello schema sopra include i seguenti campi:

  • getMovies :Questo campo restituisce un array di uno o più Movie digitare oggetti.
  • getMovie :Questo campo accetta un ID argomento e restituisce un singolo Movie digitare oggetto.

Inoltre, la Mutation tipo include un createMovie campo che accetta un title , rating e un year argomento e restituisce un Movie tipo oggetto. Questi campi rappresentano le query e le mutazioni accettate dal server GraphQL.

Quando vengono eseguite le query e le mutazioni nei tipi radice, GraphQL si aspetta che le rispettive funzioni di risoluzione raccolgano e restituiscano i dati corrispondenti al tipo restituito dello schema. Per aggiungere funzioni di risoluzione, crea un resolvers.js file nel src directory e aggiungere il seguente codice al file:

const movies = [{
  _id: "12345",
  title: "Sinder Twindler",
  year: 2022,
  rating: 6.5,
}];

export const resolvers = {
  Query: {
    getMovies: (_root, _args, _context, _info) => {
      return movies;
    },
    getMovie: (_root, { id }, _context, _info) => {
      return movies.find(({ _id }) => _id === id);
    }
  },
  Mutation: {
    createMovie: (_root, args, _context, _info) => {
      const randomId = Math.random().toString().split('.')[1];
      const newMovie = { ...args, _id: randomId }
      movies.push(newMovie);
      return newMovie;
    }
  }
}

Nel codice sopra, inizializziamo una matrice di filmati che funge da origine dati temporanea. In aggiunta a ciò, esportiamo un resolvers oggetto con Query e Mutation proprietà che corrispondono a Query e Mutation tipi nella definizione dello schema. Le due proprietà del risolutore includono funzioni che corrispondono alle operazioni dichiarate nella Query e Mutation tipi. Queste funzioni del resolver eseguono azioni specifiche sull'origine dati e restituiscono i dati richiesti.

Una funzione risolutore GraphQL accetta quattro argomenti:

  • root :questo argomento contiene i risultati di eventuali risolutori eseguiti in precedenza.
  • args :questo argomento contiene i parametri per una query GraphQL.
  • context :questo argomento contiene dati/oggetti a cui è possibile accedere/condividere tra le funzioni del risolutore.
  • info :questo argomento contiene informazioni sulla query o la mutazione GraphQL in esecuzione.

Lo schema e i resolver creati devono essere collegati a un server per diventare funzionali. Nel src directory, crea un index.js file e aggiungi la seguente parte di codice al file:

import { ApolloServer } from 'apollo-server';
import { typeDefs } from './typeDefs'
import { resolvers } from './resolvers'

const server = new ApolloServer({typeDefs, resolvers})

server.listen({ port: process.env.PORT || 4000 }).then(({ url }) => {
  console.log(`🚀 Server ready at ${url}`);
});

Il codice sopra importa e crea un'istanza di Apollo Server. Lo schema (typeDefs ) e anche i risolutori vengono importati nel file e passati all'istanza di Apollo Server. Infine, listen di Apollo Server il metodo avvia il server web sulla porta fornita o sulla porta 4000 se non viene fornita alcuna porta.

Per eseguire il server, aggiungi lo script seguente a package.json file che si trova nella directory principale:

{
  ...
  "scripts": {
    …
    "start:dev": "babel-node src/index.js"
  },
...
}

start:dev lo script precedente esegue il codice in src/index.js file utilizzando il babel-node pacchetto. Per eseguire lo script, esegui il comando seguente nella finestra del terminale:

npm run start:dev

Il comando precedente avvia il server web, che viene eseguito sulla porta 4000. L'esecuzione del comando dovrebbe restituire la risposta seguente:

🚀  Server ready at http://localhost:4000/

Per vedere la pagina di destinazione di Apollo Server, visita http://localhost:4000/ nel tuo browser. Dovresti vedere una pagina come quella qui sotto:

Nella pagina di destinazione, fai clic sul pulsante "Interroga il tuo server" per essere reindirizzato alla sandbox del browser. Dovresti vedere una pagina come quella qui sotto, con una query GraphQL precompilata:

La sandbox è composta da tre pannelli; il pannello di sinistra mostra lo schema dell'API GraphQL con le query e le mutazioni disponibili, il pannello centrale serve per scrivere ed eseguire query e il pannello di destra per visualizzare i risultati delle query. Sostituisci la query nella tua sandbox con il codice seguente:

query ExampleQuery {
  getMovies {
    _id
    title
    year
    rating
  }
}

Il codice sopra aggiunge campi extra a ExampleQuery interrogazione. Per eseguire la query, fare clic sul pulsante "ExampleQuery" per eseguire la query. Dovresti vedere la risposta nel pannello di destra.

In questa sezione è stato creato un server GraphQL con query e mutazioni. Nella sezione successiva, collegherai il server GraphQL a un database MongoDB.

Collega il server GraphQL al database Mongo

Le funzioni del risolutore nel server GraphQL attualmente recuperano i dati da un'origine dati codificata anziché dal database MongoDB creato nella prima sezione. In questa sezione, collegherai il server GraphQL al database MongoDB e creerai anche un modello di mangusta per rappresentare un documento di film su MongoDB.

Innanzitutto, crea un .env nella directory principale del progetto e aggiungere il codice seguente al file dove <username> e <password> rappresenta il tuo utente del database MongoDB e la sua password:

MONGODB_URI="mongodb+srv://<username>:<password>@apollogql-demo.kk9qw.mongodb.net/apollogql-db?retryWrites=true&w=majority"

Il codice sopra rende disponibile la stringa di connessione al database MongoDB come variabile di ambiente. Il .env il file non deve essere vincolato a git poiché contiene dati segreti.

Quindi, sostituisci il codice in src/index.js file con quanto segue:

import 'dotenv/config'
import mongoose from 'mongoose';
import { ApolloServer } from 'apollo-server';

import { typeDefs } from './typeDefs';
import { resolvers } from './resolvers';

const uri = process.env.MONGODB_URI
const main = async () => {
  await mongoose.connect(uri, { useNewUrlParser: true, useUnifiedTopology: true })
};

main()
  .then(console.log('🎉 connected to database successfully'))
  .catch(error => console.error(error));

const server = new ApolloServer({ typeDefs, resolvers })

server.listen({ port: process.env.PORT || 4000 }).then(({ url }) => {
  console.log(`🚀 Server ready at ${url}`);
});

Il codice sopra importa il dotenv config e mongoose pacchetto nel index.js file. Importazione di dotenv config crea le variabili di ambiente nel .env file accessibile tramite process.env oggetto. Il valore del MONGODB_URI si accede alla variabile di ambiente tramite process.env e memorizzato in un uri variabile e una funzione asincrona main viene dichiarato per creare una connessione al database MongoDB utilizzando il connect di mongoose funzione e il uri stringa di connessione. Il main() viene quindi chiamata la funzione per aprire una connessione al database MongoDB.

🎉 connected to database successfully
🚀  Server ready at http://localhost:4000/

Infine, crea un models nella cartella src cartella e al suo interno, crea un movie.js file. Aggiungi il codice qui sotto al file:

import mongoose from "mongoose";

export const Movie = mongoose.model("Movie", {
  title: String,
  rating: Number,
  year: Number,
});

Il codice sopra crea un Movie modello e funge da interfaccia per la creazione e la manipolazione di documenti nel database MongoDB. Questo è l'ultimo passo per rendere il database MongoDB l'origine dati per il server GraphQL. Nella sezione successiva, passerai l'origine dati del server GraphQL dall'array codificato al tuo database MongoDB.

Usa MongoDB come origine dati GraphQL

L'origine dati corrente per il server GraphQL è un array hardcoded e in questa sezione lo sostituirai con il tuo database MongoDB. Per farlo, inizia creando un dataSources nella cartella src cartella. In dataSources cartella, crea un movies.js file e aggiungi il seguente codice al file:

import { MongoDataSource } from 'apollo-datasource-mongodb'

export default class Movies extends MongoDataSource {
  async getMovies() {
    return await this.model.find();
  }

  async getMovie(id) {
    return await this.findOneById(id);
  }

  async createMovie({ title, rating, year }) {
    return await this.model.create({ title, rating, year });
  }
}

Il codice sopra dichiara un Movie classe di origine dati che estende il MongoDataSource classe fornita da apollo-datasource-mongodb pacchetto. I Movie l'origine dati contiene tre metodi per ciascuna delle query e delle mutazioni esistenti. getMovies e createMovie i metodi utilizzano il modello del filmato creato nella sezione precedente per leggere e inserire dati nel database MongoDB e getMovie il metodo utilizza il findOneById metodo fornito da MongoDataSource class per recuperare un documento dalla raccolta MongoDB che corrisponde all'id fornito argomento.

Quindi, sostituisci il codice in src/index.js file con il codice qui sotto:

import 'dotenv/config'
import mongoose from 'mongoose';
import { ApolloServer } from 'apollo-server';

import { typeDefs } from './typeDefs';
import { resolvers } from './resolvers';
import { Movie as MovieModel } from './models/movie';
import Movies from './dataSources/movies';

const uri = process.env.MONGODB_URI
const main = async () => {
  await mongoose.connect(uri, { useNewUrlParser: true, useUnifiedTopology: true })
};

main()
  .then(console.log('🎉 connected to database successfully'))
  .catch(error => console.error(error));

const dataSources = () => ({
  movies: new Movies(MovieModel),
});

const server = new ApolloServer({ typeDefs, resolvers, dataSources })

server.listen({ port: process.env.PORT || 4000 }).then(({ url }) => {
  console.log(`🚀 Server ready at ${url}`);
});

Il codice aggiornato sopra importa il Movie modello e i Movie classe di origine dati in src/index.js file. Dopo la connessione al database MongoDB, un dataSources viene creata la funzione. Questa funzione restituisce un oggetto contenente un'istanza dei Movie origine dati che riceve il Movie modello come parametro. Le dataSources la funzione viene quindi passata all'istanza di Apollo Server, creando i Movies istanza di origine dati disponibile all'interno di ogni funzione di risoluzione.

Per sostituire l'origine dati codificata con il Movie origine dati, sostituire il codice in src/resolvers.js file con il codice qui sotto:

export const resolvers = {
  Query: {
    getMovies: async (_, _args, { dataSources: { movies } }) => {
      return movies.getMovies();
    },
    getMovie: async (_, { id }, { dataSources: { movies } }) => {
      return movies.getMovie(id);
    }
  },
  Mutation: {
    createMovie: async (_, args, { dataSources: { movies } }) => {
      return movies.createMovie(args)
    }
  }
}

Nel codice aggiornato sopra, i Movie istanza dell'origine dati passata ad Apollo Server in src/index.js è disponibile nelle funzioni del resolver tramite dataSources proprietà dell'oggetto contesto condiviso. Ciascuna funzione del resolver richiama il rispettivo metodo nell'origine dati per eseguire l'operazione specificata sul database MongoDB.

Qualsiasi query eseguita a questo punto restituirà un risultato vuoto poiché il database MongoDB è attualmente vuoto. Riavvia il tuo server, quindi visita il tuo account Mongo Atlas nel tuo browser. Nella pagina "Distribuzioni database" di MongoDB, seleziona il cluster di database e fai clic sulla scheda "Raccolte". Nella scheda "Raccolte", fai clic sul pulsante "INSERIRE DOCUMENTO" e aggiungi tutti i documenti di film che desideri.

Nella sandbox di Apollo Server, esegui ExampleQuery dalla sezione precedente. Dovresti ottenere un elenco di tutti i documenti del film nella tua raccolta Mongo DB. In questa sezione, hai utilizzato il tuo database MongoDB come origine dati per il tuo server GraphQL. Nella prossima sezione, distribuirai il tuo server GraphQL online su Koyeb.

Distribuisci su Koyeb

Il primo passo verso la distribuzione del server GraphQL su Koyeb consiste nell'aggiungere gli script npm necessari per creare il codice in produzione. Aggiungi i seguenti script di seguito al tuo package.json file:

"scripts": {
  ...
  "prebuild": "rimraf dist && mkdir dist",
  "build": "babel src -d dist",
  "start": "node ./dist/index.js"
  }

I tre script npm aggiunti sopra includono:

  • Un prebuild script per assicurarsi che sia presente una dist vuota directory prima della build lo script viene eseguito.
  • Una build script che traspone tutto il codice in src directory nella sintassi JavaScript ES5 nella dist directory con l'aiuto di babel pacchetto.
  • Un start script che avvia il server.

Quindi, crea un repository GitHub per il tuo server GraphQL, quindi esegui i comandi seguenti nella finestra del tuo terminale:

git add --all
git commit -m "Complete GraphQL server with MongoDB data source."
git remote add origin [email protected]<YOUR_GITHUB_USERNAME>/<YOUR_REPOSITORY_NAME>.git
git branch -M main
git push -u origin main

Sul tuo pannello di controllo Koyeb, vai a Secrets scheda e crea un nuovo segreto. Inserisci MONGODB_URI come nome segreto e la stringa di connessione MongoDB come valore. Quindi, vai a Overview scheda e fai clic sul pulsante "Crea app" per avviare il processo di creazione dell'app.

Nella pagina di creazione dell'app:

  • Seleziona GitHub come metodo di distribuzione.
  • Nel menu a discesa dei repository, seleziona il repository GitHub per il tuo codice.
  • Seleziona il ramo che desideri distribuire. Per esempio. main .
  • Nella sezione delle variabili d'ambiente, fai clic sul pulsante Aggiungi variabile d'ambiente.
  • Seleziona il Secret digita, inserisci MONGODB_URI come chiave e seleziona il MONGODB_URI segreto creato in precedenza come valore.
  • Aggiungi una variabile d'ambiente in chiaro con la chiave PORT e il valore 8080 .
  • Assegna un nome alla tua app. Per esempio. graphql-apollo-server e fai clic sul pulsante "Crea app".

Durante la creazione dell'app, run e build le opzioni di comando sono state ignorate poiché la piattaforma Koyeb è in grado di rilevare la build e start script nel package.json file ed eseguirli automaticamente. Facendo clic sul pulsante "Crea app" si reindirizza alla pagina di distribuzione, dove è possibile monitorare il processo di distribuzione dell'app. Una volta completata la distribuzione e superati tutti i controlli di integrità necessari, puoi accedere al tuo URL pubblico.

Testa la tua API GraphQL

Utilizzando il tuo strumento di test API preferito o questo playground online di GraphiQL, crea un getMovies query GraphQL al tuo URL pubblico. Dovresti ottenere una risposta di tutti i documenti di film sul tuo database MongoDB.

Conclusione

Questo è tutto! Hai creato e distribuito con successo un server GraphQL con Apollo Server e un'origine dati MongoDB su Koyeb. Sentiti libero di aggiungere più query e mutazioni al tuo server GraphQL. Dal momento che abbiamo distribuito su Koyeb utilizzando la distribuzione basata su git, una nuova build verrà automaticamente attivata e distribuita su Koyeb ogni volta che invii le modifiche al tuo repository GitHub.

Le modifiche saranno attive non appena la distribuzione avrà superato tutti i controlli di integrità necessari. In caso di errore durante la distribuzione, Koyeb mantiene l'ultima distribuzione funzionante in produzione per garantire che l'applicazione sia sempre attiva e funzionante.

Grazie all'implementazione su Koyeb, la nostra applicazione beneficia del bilanciamento del carico globale nativo, della scalabilità automatica, della riparazione automatica e della crittografia HTTPS (SSL) automatica senza alcuna configurazione da parte nostra.

Se desideri guardare il codice per l'applicazione demo, puoi trovarlo qui.