Share via


Connettersi a Database SQL di Azure ed eseguire query usando Node.js e il pacchetto mssql npm

Si applica a:database SQL di Azure

Questa guida di avvio rapido descrive come connettere un'applicazione a un database in Database SQL di Azure ed eseguire query usando .Node.js e mssql. Questa guida di avvio rapido segue l'approccio senza password consigliato per connettersi al database.

Connessioni senza password per gli sviluppatori

Le connessioni senza password offrono un meccanismo più sicuro per l'accesso alle risorse di Azure. I seguenti passaggi generali vengono usati per connettersi a database SQL di Azure tramite le connessioni senza password in questo articolo:

  • Preparare l'ambiente all'autenticazione senza password.
    • Per un ambiente locale: viene usata l'identità personale. Questa identità può essere estratta da un IDE, dall'interfaccia della riga di comando o da altri strumenti di sviluppo locali.
    • Per un ambiente cloud: viene usata un'identità gestita.
  • Eseguire l'autenticazione nell'ambiente usando DefaultAzureCredential dalla libreria di identità di Azure per ottenere credenziali verificate.
  • Usare le credenziali verificate per creare oggetti client SDK di Azure per l'accesso alle risorse.

Altre informazioni sulle connessioni senza password sono disponibili nell'hub senza password.

Prerequisiti

Configurazione del server database

La connessione sicura senza password a Database SQL di Azure richiede determinate configurazioni del database. Verificare le impostazioni seguenti nel server logico in Azure per connettersi correttamente a Database SQL di Azure in ambienti locali e ospitati:

  1. Per le connessioni di sviluppo locale, verificare che il server logico sia configurato per consentire all'indirizzo IP del computer locale e ad altri servizi di Azure di connettersi:

    • Passare alla pagina Rete del server.

    • Attivare o disattivare il pulsante di opzione Reti selezionate per visualizzare ulteriori opzioni di configurazione.

    • Selezionare Aggiungere l'indirizzo IPv4 client (xx.xx.xx.xx.xx) per aggiungere una regola del firewall che consentirà le connessioni dall'indirizzo IPv4 del computer locale. In alternativa, è anche possibile selezionare + Aggiungi una regola del firewall per immettere un indirizzo IP specifico a propria scelta.

    • Selezionare la casella di controllo Consenti alle risorse e ai servizi di Azure di accedere a questo server.

      Screenshot che mostra come configurare le regole del firewall.

      Avviso

      L'abilitazione dell'impostazione Consenti a servizi e risorse di Azure di accedere a questo server non è una procedura di protezione consigliata per gli scenari di produzione. Le applicazioni reali devono implementare approcci più sicuri, ad esempio restrizioni firewall più avanzate o configurazioni di reti virtuali.

      Per altre informazioni sulle configurazioni di sicurezza del database, vedere le seguenti risorse:

  2. Al server deve essere abilitata anche l'autenticazione Microsoft Entra e deve essere assegnato un account amministratore di Microsoft Entra. Per le connessioni di sviluppo locali, l'account amministratore di Microsoft Entra deve essere un account con il quale è possibile accedere localmente anche a Visual Studio o all'interfaccia della riga di comando di Azure. È possibile verificare se nel server è abilitata l'autenticazione Microsoft Entra dalla pagina Microsoft Entra ID del server logico.

    Screenshot che mostra come abilitare l'autenticazione di Microsoft Entra.

  3. Se si usa un account Azure personale, assicurarsi di avere impostato Microsoft Entra e che sia configurato per Database SQL di Azure per poter assegnare l'account come amministratore del server. Se si usa un account aziendale, è probabile che Microsoft Entra ID sia già configurato automaticamente.

Creare il progetto

I passaggi illustrati in questa sezione creano un'API REST Node.js.

  1. Creare una nuova directory per il progetto e passare alla directory.

  2. Inizializzare il progetto eseguendo il seguente comando nel terminale:

    npm init -y
    
  3. Installare i pacchetti necessari usati nel codice di esempio di questo articolo:

    npm install mssql swagger-ui-express yamljs
    
  4. Installare il pacchetto di sviluppo usato nel codice di esempio di questo articolo:

    npm install --save-dev dotenv 
    
  5. Aprire il progetto in Visual Studio Code.

    code .
    
  6. Aprire il file package.json e aggiungere la proprietà e il valore seguenti dopo la proprietà name per configurare il progetto per i moduli ESM.

    "type": "module",
    

Creare il codice dell'applicazione Express.js

Per creare l'applicazione OpenAPI Express.js verranno creati vari file:

File Descrizione
.env.development File di ambiente di solo sviluppo locale.
index.js File dell'applicazione principale che avvia l'app Express.js sulla porta 3000.
person.js File API route /person Express.js per gestire le operazioni CRUD.
openapi.js Route /api-docs Express.js per l'interfaccia utente di OpenAPI Explorer. La radice reindirizza a questa route.
openApiSchema.yml File di schema OpenAPI 3.0 che definisce l'API Person.
config.js File di configurazione per leggere le variabili di ambiente e costruire l'oggetto connessione mssql adeguato.
database.js Classe di database per gestire le operazioni CRUD di SQL di Azure tramite il pacchetto npm mssql.
./vscode/settings.json Ignorare i file in base al criterio GLOB durante la distribuzione.
  1. Creare un file index.js e aggiungere il codice seguente:

    import express from 'express';
    import { config } from './config.js';
    import Database from './database.js';
    
    // Import App routes
    import person from './person.js';
    import openapi from './openapi.js';
    
    const port = process.env.PORT || 3000;
    
    const app = express();
    
    // Development only - don't do in production
    // Run this to create the table in the database
    if (process.env.NODE_ENV === 'development') {
      const database = new Database(config);
      database
        .executeQuery(
          `CREATE TABLE Person (id int NOT NULL IDENTITY, firstName varchar(255), lastName varchar(255));`
        )
        .then(() => {
          console.log('Table created');
        })
        .catch((err) => {
          // Table may already exist
          console.error(`Error creating table: ${err}`);
        });
    }
    
    // Connect App routes
    app.use('/api-docs', openapi);
    app.use('/persons', person);
    app.use('*', (_, res) => {
      res.redirect('/api-docs');
    });
    
    // Start the server
    app.listen(port, () => {
      console.log(`Server started on port ${port}`);
    });
    
  2. Creare un file route person.js e aggiungere il codice seguente:

    import express from 'express';
    import { config } from './config.js';
    import Database from './database.js';
    
    const router = express.Router();
    router.use(express.json());
    
    // Development only - don't do in production
    console.log(config);
    
    // Create database object
    const database = new Database(config);
    
    router.get('/', async (_, res) => {
      try {
        // Return a list of persons
        const persons = await database.readAll();
        console.log(`persons: ${JSON.stringify(persons)}`);
        res.status(200).json(persons);
      } catch (err) {
        res.status(500).json({ error: err?.message });
      }
    });
    
    router.post('/', async (req, res) => {
      try {
        // Create a person
        const person = req.body;
        console.log(`person: ${JSON.stringify(person)}`);
        const rowsAffected = await database.create(person);
        res.status(201).json({ rowsAffected });
      } catch (err) {
        res.status(500).json({ error: err?.message });
      }
    });
    
    router.get('/:id', async (req, res) => {
      try {
        // Get the person with the specified ID
        const personId = req.params.id;
        console.log(`personId: ${personId}`);
        if (personId) {
          const result = await database.read(personId);
          console.log(`persons: ${JSON.stringify(result)}`);
          res.status(200).json(result);
        } else {
          res.status(404);
        }
      } catch (err) {
        res.status(500).json({ error: err?.message });
      }
    });
    
    router.put('/:id', async (req, res) => {
      try {
        // Update the person with the specified ID
        const personId = req.params.id;
        console.log(`personId: ${personId}`);
        const person = req.body;
    
        if (personId && person) {
          delete person.id;
          console.log(`person: ${JSON.stringify(person)}`);
          const rowsAffected = await database.update(personId, person);
          res.status(200).json({ rowsAffected });
        } else {
          res.status(404);
        }
      } catch (err) {
        res.status(500).json({ error: err?.message });
      }
    });
    
    router.delete('/:id', async (req, res) => {
      try {
        // Delete the person with the specified ID
        const personId = req.params.id;
        console.log(`personId: ${personId}`);
    
        if (!personId) {
          res.status(404);
        } else {
          const rowsAffected = await database.delete(personId);
          res.status(204).json({ rowsAffected });
        }
      } catch (err) {
        res.status(500).json({ error: err?.message });
      }
    });
    
    export default router;
    
    
  3. Creare un file route opanapi.js e aggiungere il codice seguente per esplorare l’interfaccia utente di OpenAPI:

    import express from 'express';
    import { join, dirname } from 'path';
    import swaggerUi from 'swagger-ui-express';
    import yaml from 'yamljs';
    import { fileURLToPath } from 'url';
    
    const __dirname = dirname(fileURLToPath(import.meta.url));
    
    const router = express.Router();
    router.use(express.json());
    
    const pathToSpec = join(__dirname, './openApiSchema.yml');
    const openApiSpec = yaml.load(pathToSpec);
    
    router.use('/', swaggerUi.serve, swaggerUi.setup(openApiSpec));
    
    export default router;
    
  4. Creare un file di schema openApiSchema.yml e aggiungere il YAML seguente:

    openapi: 3.0.0
    info:
      version: 1.0.0
      title: Persons API
    paths:
      /persons:
        get:
          summary: Get all persons
          responses:
            '200':
              description: OK
              content:
                application/json:
                  schema:
                    type: array
                    items:
                      $ref: '#/components/schemas/Person'
        post:
          summary: Create a new person
          requestBody:
            required: true
            content:
              application/json:
                schema:
                  $ref: '#/components/schemas/Person'
          responses:
            '201':
              description: Created
              content:
                application/json:
                  schema:
                    $ref: '#/components/schemas/Person'
      /persons/{id}:
        parameters:
          - name: id
            in: path
            required: true
            schema:
              type: integer
        get:
          summary: Get a person by ID
          responses:
            '200':
              description: OK
              content:
                application/json:
                  schema:
                    $ref: '#/components/schemas/Person'
            '404':
              description: Person not found
        put:
          summary: Update a person by ID
          requestBody:
            required: true
            content:
              application/json:
                schema:
                  $ref: '#/components/schemas/Person'
          responses:
            '200':
              description: OK
              content:
                application/json:
                  schema:
                    $ref: '#/components/schemas/Person'
            '404':
              description: Person not found
        delete:
          summary: Delete a person by ID
          responses:
            '204':
              description: No Content
            '404':
              description: Person not found
    components:
      schemas:
        Person:
          type: object
          properties:
            id:
              type: integer
              readOnly: true
            firstName:
              type: string
            lastName:
              type: string
    

Configurare l'oggetto connessione mssql

Il pacchetto mssql implementa la connessione a database SQL di Azure fornendo un'impostazione di configurazione per un tipo di autenticazione.

  1. In Visual Studio Code, creare un file config.js e aggiungere il codice di configurazione mssql seguente per l'autenticazione a database SQL di Azure.

    import * as dotenv from 'dotenv';
    dotenv.config({ path: `.env.${process.env.NODE_ENV}`, debug: true });
    
    const server = process.env.AZURE_SQL_SERVER;
    const database = process.env.AZURE_SQL_DATABASE;
    const port = parseInt(process.env.AZURE_SQL_PORT);
    const type = process.env.AZURE_SQL_AUTHENTICATIONTYPE;
    
    export const config = {
        server,
        port,
        database,
        authentication: {
            type
        },
        options: {
            encrypt: true
        }
    };
    
  2. Creare un file env.development per le variabili di ambiente locali, aggiungere il testo seguente e aggiornare con i propri valori per <YOURSERVERNAME> e <YOURDATABASENAME>.

    AZURE_SQL_SERVER=<YOURSERVERNAME>.database.windows.net
    AZURE_SQL_DATABASE=<YOURDATABASENAME>
    AZURE_SQL_PORT=1433
    AZURE_SQL_AUTHENTICATIONTYPE=azure-active-directory-default
    

Nota

Gli oggetti di configurazione senza password sono sicuri per l’esecuzione del commit nel controllo del codice sorgente, poiché non contengono segreti quali nomi utente, password o chiavi di accesso.

  1. Creare una cartella .vscode e creare un file settings.json nella cartella.

  2. Aggiungere quanto segue per ignorare le variabili di ambiente e le dipendenze durante la distribuzione in zip.

    {
        "appService.zipIgnorePattern": ["./.env*","node_modules{,/**}"]
    }
    

Aggiungere il codice per connettersi al database SQL di Azure

  1. Creare un file database.js e aggiungere il codice seguente:

    import sql from 'mssql';
    
    export default class Database {
      config = {};
      poolconnection = null;
      connected = false;
    
      constructor(config) {
        this.config = config;
        console.log(`Database: config: ${JSON.stringify(config)}`);
      }
    
      async connect() {
        try {
          console.log(`Database connecting...${this.connected}`);
          if (this.connected === false) {
            this.poolconnection = await sql.connect(this.config);
            this.connected = true;
            console.log('Database connection successful');
          } else {
            console.log('Database already connected');
          }
        } catch (error) {
          console.error(`Error connecting to database: ${JSON.stringify(error)}`);
        }
      }
    
      async disconnect() {
        try {
          this.poolconnection.close();
          console.log('Database connection closed');
        } catch (error) {
          console.error(`Error closing database connection: ${error}`);
        }
      }
    
      async executeQuery(query) {
        await this.connect();
        const request = this.poolconnection.request();
        const result = await request.query(query);
    
        return result.rowsAffected[0];
      }
    
      async create(data) {
        await this.connect();
        const request = this.poolconnection.request();
    
        request.input('firstName', sql.NVarChar(255), data.firstName);
        request.input('lastName', sql.NVarChar(255), data.lastName);
    
        const result = await request.query(
          `INSERT INTO Person (firstName, lastName) VALUES (@firstName, @lastName)`
        );
    
        return result.rowsAffected[0];
      }
    
      async readAll() {
        await this.connect();
        const request = this.poolconnection.request();
        const result = await request.query(`SELECT * FROM Person`);
    
        return result.recordsets[0];
      }
    
      async read(id) {
        await this.connect();
    
        const request = this.poolconnection.request();
        const result = await request
          .input('id', sql.Int, +id)
          .query(`SELECT * FROM Person WHERE id = @id`);
    
        return result.recordset[0];
      }
    
      async update(id, data) {
        await this.connect();
    
        const request = this.poolconnection.request();
    
        request.input('id', sql.Int, +id);
        request.input('firstName', sql.NVarChar(255), data.firstName);
        request.input('lastName', sql.NVarChar(255), data.lastName);
    
        const result = await request.query(
          `UPDATE Person SET firstName=@firstName, lastName=@lastName WHERE id = @id`
        );
    
        return result.rowsAffected[0];
      }
    
      async delete(id) {
        await this.connect();
    
        const idAsNumber = Number(id);
    
        const request = this.poolconnection.request();
        const result = await request
          .input('id', sql.Int, idAsNumber)
          .query(`DELETE FROM Person WHERE id = @id`);
    
        return result.rowsAffected[0];
      }
    }
    

Test dell'app in locale

L'app è pronta per essere testata a livello locale. Assicurarsi di aver eseguito l'accesso ad Azure Cloud in Visual Studio Code con lo stesso account che è stato impostato come amministratore per il database.

  1. Eseguire l'applicazione con il comando seguente. L'app si avvia sulla porta 3000.

    NODE_ENV=development node index.js
    

    La tabella Person viene creata nel database quando si esegue questa applicazione.

  2. In un browser, passare a OpenAPI Explorer da http://localhost:3000.

  3. Nella pagina dell'interfaccia utente di Swagger, espandere il metodo POST e selezionare Prova.

  4. Modificare il codice JSON di esempio in modo da includere i valori per le proprietà. La proprietà ID viene ignorata.

    Screenshot che mostra come testare l'API.

  5. Selezionare Esegui per aggiungere un nuovo record al database. L'API restituisce una risposta di esito positivo.

  6. Espandere il metodo GET nella pagina dell'interfaccia utente di Swagger, quindi selezionare Prova. Selezionare Esegui e, in questo modo, viene restituita la persona appena creata.

Distribuire nel Servizio app di Azure

L'app è pronta per essere distribuita in Azure. Visual Studio Code può creare un servizio app di Azure per distribuire l'applicazione in un singolo flusso di lavoro.

  1. Verificare che l'app sia stata arrestata.

  2. Se non è già stato effettuato l’accesso ad Azure, procedere ora selezionando il comando Azure: Accedi ad Azure Cloud nel riquadro comandi (Ctrl + MAIUSC + P)

  3. Nella finestra Azure Explorer di Visual Studio Code, fare clic con il pulsante destro del mouse sul nodo Servizi app e scegliere Crea nuova app Web (avanzata).

  4. Usare la tabella seguente per creare il servizio app:

    Richiesta Valore
    Immettere un nome univoco globale per la nuova app Web. Immettere un prompt, ad esempio azure-sql-passwordless. Posporre una stringa univoca, ad esempio 123.
    Selezionare un gruppo di risorse per le nuove risorse. Selezionare +Crea nuovo gruppo di risorse, quindi selezionare il nome predefinito.
    Selezionare uno stack di runtime. Selezionare una versione LTS dello stack di Node.js.
    Selezionare un sistema operativo. Selezionare Linux.
    Select a location for new resources. Selezionare una posizione nelle vicinanze.
    Selezionare un piano di servizio app Linux. Selezionare Crea nuovo piano di servizio app, quindi selezionare il nome predefinito.
    Selezionare un piano tariffario. Selezionare Gratuito (F1).
    Selezionare una risorsa di Application Insights per l'app. Selezionare Ignora per adesso.
  5. Attendere la ricezione della notifica che l'app è stata creata prima di continuare.

  6. In Azure Explorer espandere il nodo Servizi app e fare clic con il pulsante destro del mouse sulla nuova app.

  7. Selezionare Distribuisci nell'app Web.

    Screenshot di Visual Studio Code in Azure Explorer con l'elemento Distribuire all’app Web evidenziato.

  8. Selezionare la cartella radice del progetto JavaScript.

  9. Quando appare il popup di Visual Studio Code, selezionare Distribuisci.

Al termine della distribuzione, l'app non funziona correttamente in Azure. È comunque necessario configurare la connessione protetta tra il servizio app e il database SQL per recuperare i dati.

Connettere il servizio app al database SQL di Azure

Per connettere l'istanza del servizio app a Database SQL di Azure sono necessari i passaggi seguenti:

  1. Creare un'identità gestita per il servizio app.
  2. Creare un utente del database SQL e associarlo all'identità gestita del servizio app.
  3. Assegnare ruoli SQL all'utente del database che consentano di leggere, scrivere e potenzialmente di ottenere altre autorizzazioni.

Sono disponibili vari strumenti per implementare questi passaggi:

Connettore di servizi è uno strumento che semplifica le connessioni autenticate tra vari servizi in Azure. Connettore di servizi supporta attualmente la connessione di un servizio app a un database SQL di Azure tramite l'interfaccia della riga di comando di Azure mediante il comando az webapp connection create sql. Questo singolo comando completa i tre passaggi indicati precedentemente.

Creare l'identità gestita con Connettore di servizi

Eseguire il comando seguente in Cloud Shell nel portale di Azure. Cloud Shell include la versione più recente dell'interfaccia della riga di comando di Azure. Sostituire le variabili in <> con i propri valori.

az webapp connection create sql \
    -g <app-service-resource-group> \
    -n <app-service-name> \
    --tg <database-server-resource-group> \
    --server <database-server-name> \
    --database <database-name> \
    --system-identity

Verificare le impostazioni dell'app Servizi app

È possibile verificare le modifiche apportate dal connettore di servizi nelle impostazioni dei servizi app.

  1. In Visual Studio Code, in Azure Explorer fare clic con il pulsante destro del mouse su Servizi app e scegliere Apri nel portale.

  2. Passare alla pagina Identità per il servizio app. Nella scheda Assegnata dal sistema , lo Stato deve essere impostato su Attivato. Questo valore indica che è stata abilitata un'identità gestita assegnata dal sistema per l'app.

  3. Passare alla pagina Configurazione per il servizio app. Nella scheda Impostazioni applicazione dovrebbero essere visualizzate diverse variabili di ambiente, già presenti nell'oggetto di configurazione mssql.

    • AZURE_SQL_SERVER
    • AZURE_SQL_DATABASE
    • AZURE_SQL_PORT
    • AZURE_SQL_AUTHENTICATIONTYPE

    Non eliminare o modificare i nomi o i valori delle proprietà.

Testare l'applicazione distribuita

Passare all'URL dell'app per testare il funzionamento della connessione al database SQL di Azure. È possibile individuare l'URL dell'app nella pagina di panoramica del servizio app.

La persona creata in locale verrà visualizzata nel browser. Complimenti. L'applicazione è ora connessa al database SQL di Azure in ambienti locali e ospitati.

Suggerimento

Se si ottiene un messaggio 500 - Errore interno del server durante il test, ciò potrebbe essere dovuto alle configurazioni di rete del database. Verificare che il server logico sia configurato con le impostazioni illustrate nella sezione Configurare il database.

Pulire le risorse

Al termine dell'utilizzo del database SQL di Azure, eliminare la risorsa per evitare costi accidentali.

  1. Nella barra di ricerca del portale di Azure, cercare Azure SQL e selezionare il risultato corrispondente.

  2. Individuare e selezionare il proprio database nell'elenco dei database.

  3. Nella pagina Panoramica del database SQL di Azure, selezionare Elimina.

  4. Nella pagina Azure: vuoi davvero eliminare... che viene visualizzata, digitare il nome del database per confermare, quindi selezionare Elimina.

Codice di esempio

Il codice di esempio di questa applicazione è disponibile in GitHub.

Passaggi successivi