Nozioni di base su AWS

Creazione di un'applicazione Web serverless

con AWS Lambda, Amazon API Gateway, AWS Amplify, Amazon DynamoDB e Amazon Cognito

Modulo 3: Back-end serverless del servizio

Utilizzerai AWS Lambda e Amazon DynamoDB per creare un processo back-end per gestire le richieste della tua applicazione Web.

Panoramica

In questo modulo, utilizzerai AWS Lambda e Amazon DynamoDB per creare un processo di back-end per gestire le richieste della tua applicazione Web. L'applicazione browser che hai distribuito nel primo modulo consente agli utenti di richiedere l'invio di un unicorn a una posizione desiderata. Per soddisfare questi requisiti, il linguaggio JavaScript in esecuzione nel browser dovrà chiamare un servizio in esecuzione nel cloud.

Panoramica dell'architettura

Panoramica dell'architettura

Dovrai implementare una funzione Lambda che verrà chiamata ogni volta che un utente richiede un unicorno. La funzione selezionerà un unicorno dal parco istanze, registrerà la richiesta in una tabella DynamoDB e quindi risponderà all'applicazione front-end con i dettagli sull'unicorno in fase di invio.

La funzione viene chiamata dal browser utilizzando Gateway Amazon API. Dovrai implementare tale connessione nel prossimo modulo. In questo modulo, ti occuperai solo del test della funzione in isolamento.

 Tempo per il completamento

30 minuti

 Servizi utilizzati

Implementazione

  • Usa la console Amazon DynamoDB per creare una nuova tabella DynamoDB. 

    1. Nella console Amazon DynamoDB, scegli Crea tabella.
    2. Per Nome tabella, immetti Rides. Questo campo fa distinzione tra minuscole e maiuscole.
    3. Per Chiave di partizione, immetti RideId e seleziona Stringa per il tipo di chiave. Questo campo fa distinzione tra minuscole e maiuscole.
    4. Nella sezione Impostazioni tabella, assicurati che sia selezionato Impostazioni predefinite e scegli Crea tabella
    5. Nella pagina Tabelle, attendi il completamento della creazione della tabella. Una volta completato, lo stato sarà Attivo. Seleziona il nome della tabella.
    6. Nella scheda Panoramica > Informazioni generali della nuova tabella, scegli Informazioni aggiuntive. Copia l'ARN. Questo verrà utilizzato nella sezione successiva.
  • A ogni funzione Lambda è associato un ruolo IAM, che definisce con quali altri servizi AWS alla funzione è concesso interagire. Ai fini di questo tutorial, dovrai creare un ruolo IAM che conceda alla funzione Lambda l'autorizzazione a scrivere log in File di log Amazon CloudWatch e l'accesso per scrivere voci nella tabella DynamoDB.

    1. Nella console IAM, seleziona Ruoli nel riquadro di navigazione a sinistra, quindi scegli Crea ruolo.
    2. Nella sezione Tipo di entità attendibile, seleziona Servizio AWS. Per Caso d’uso, seleziona Lambda, quindi scegli Avanti
      Nota: la selezione di un tipo di ruolo comporta la creazione automatica di una policy di attendibilità per il ruolo che consente ai servizi AWS di assumere questo ruolo per conto tuo. Se si stava creando questo ruolo tramite la CLI, AWS CloudFormation o un altro meccanismo, sarà necessario specificare direttamente una policy di attendibilità.
    3. Immetti AWSLambdaBasicExecutionRole nella casella di testo di filtro, quindi premi Invio
    4. Seleziona la casella di controllo accanto al nome della policy AWSLambdaBasicExecutionRole e scegli Avanti.
    5. Immetti WildRydesLambda per Nome ruolo. Mantieni le impostazioni predefinite per gli altri parametri.
    6. Scegli Crea ruolo.
    7. Nella casella di filtro della pagina Ruoli, digita WildRydesLambda e seleziona il nome del ruolo appena creato.
    8. Nella scheda Autorizzazioni, scegli Aggiungi autorizzazioni, quindi scegli Crea policy in linea.
    9. Nella sezione Seleziona un servizio, digita DynamoDB nella barra di ricerca e seleziona DynamoDB quando viene visualizzato.
    10. Scegli Seleziona operazioni.
    11. Nella sezione Operazioni consentite, digita PutItem nella barra di ricerca e seleziona la casella di controllo accanto a PutItem quando viene visualizzata.
    12. Nella sezione Risorse, con l’opzione Specifica selezionata, scegli il link Aggiungi ARN.
    13. Seleziona la scheda Testo. Incolla l'ARN della tabella che hai creato in DynamoDB (Fase 6 nella sezione precedente) e scegli Aggiungi ARN.
    14. Scegli Avanti.
    15. Immetti DynamoDBWriteAccess come nome della policy e scegli Crea policy.
  • AWS Lambda eseguirà il tuo codice in risposta a eventi come una richiesta HTTP. In questa fase, procederai alla creazione della funzione principale che elaborerà le richieste API dall'applicazione Web per inviare un unicorn. Nel prossimo modulo utilizzerai Amazon API Gateway per creare un'API RESTful che esporrà un endpoint HTTP che può essere chiamato dai browser degli utenti. Quindi, collegherai la funzione Lambda creata in questa fase all'API per creare un back-end totalmente funzionale per la tua applicazione Web.

    Utilizza la console AWS Lambda per creare una nuova funzione Lambda denominata RequestUnicorn che elaborerà le richieste API. Per il codice funzione, utilizza la seguente implementazione di esempio requestUnicorn.js fornita. È sufficiente copiare dal file e incollare nell'editor della console AWS Lambda.

    Accertati di configurare la funzione per l'utilizzo del ruolo IAM WildRydesLambda creato nella sezione precedente.

    1. Nella console AWS Lambda, scegli Crea una funzione.
    2. Mantieni selezionata la scheda predefinita Crea da zero.
    3. Specifica RequestUnicorn nel campo Nome funzione.
    4. Seleziona Node.js 16.x per il Runtime (le versioni più recenti di Node.js non funzioneranno in questo tutorial).
    5. Seleziona Usa un ruolo esistente dal menu a discesa Modifica ruolo di esecuzione predefinito.
    6. Seleziona WildRydesLambda nell'elenco a discesa Ruolo esistente.
    7. Fai clic su Crea funzione.
    8. Scorri fino alla sezione Origine codice e sostituisci il codice esistente nell'editor di codici index.js con i contenuti di requestUnicorn.js. Il seguente blocco di codice visualizza il file requestUnicorn.js. Copia e incolla questo codice nella scheda index.js dell'editor di codice.
    const randomBytes = require('crypto').randomBytes;
    const AWS = require('aws-sdk');
    const ddb = new AWS.DynamoDB.DocumentClient();
    
    const fleet = [
        {
            Name: 'Angel',
            Color: 'White',
            Gender: 'Female',
        },
        {
            Name: 'Gil',
            Color: 'White',
            Gender: 'Male',
        },
        {
            Name: 'Rocinante',
            Color: 'Yellow',
            Gender: 'Female',
        },
    ];
    
    exports.handler = (event, context, callback) => {
        if (!event.requestContext.authorizer) {
          errorResponse('Authorization not configured', context.awsRequestId, callback);
          return;
        }
    
        const rideId = toUrlString(randomBytes(16));
        console.log('Received event (', rideId, '): ', event);
    
        // Because we're using a Cognito User Pools authorizer, all of the claims
        // included in the authentication token are provided in the request context.
        // This includes the username as well as other attributes.
        const username = event.requestContext.authorizer.claims['cognito:username'];
    
        // The body field of the event in a proxy integration is a raw string.
        // In order to extract meaningful values, we need to first parse this string
        // into an object. A more robust implementation might inspect the Content-Type
        // header first and use a different parsing strategy based on that value.
        const requestBody = JSON.parse(event.body);
    
        const pickupLocation = requestBody.PickupLocation;
    
        const unicorn = findUnicorn(pickupLocation);
    
        recordRide(rideId, username, unicorn).then(() => {
            // You can use the callback function to provide a return value from your Node.js
            // Lambda functions. The first parameter is used for failed invocations. The
            // second parameter specifies the result data of the invocation.
    
            // Because this Lambda function is called by an API Gateway proxy integration
            // the result object must use the following structure.
            callback(null, {
                statusCode: 201,
                body: JSON.stringify({
                    RideId: rideId,
                    Unicorn: unicorn,
                    Eta: '30 seconds',
                    Rider: username,
                }),
                headers: {
                    'Access-Control-Allow-Origin': '*',
                },
            });
        }).catch((err) => {
            console.error(err);
    
            // If there is an error during processing, catch it and return
            // from the Lambda function successfully. Specify a 500 HTTP status
            // code and provide an error message in the body. This will provide a
            // more meaningful error response to the end client.
            errorResponse(err.message, context.awsRequestId, callback)
        });
    };
    
    // This is where you would implement logic to find the optimal unicorn for
    // this ride (possibly invoking another Lambda function as a microservice.)
    // For simplicity, we'll just pick a unicorn at random.
    function findUnicorn(pickupLocation) {
        console.log('Finding unicorn for ', pickupLocation.Latitude, ', ', pickupLocation.Longitude);
        return fleet[Math.floor(Math.random() * fleet.length)];
    }
    
    function recordRide(rideId, username, unicorn) {
        return ddb.put({
            TableName: 'Rides',
            Item: {
                RideId: rideId,
                User: username,
                Unicorn: unicorn,
                RequestTime: new Date().toISOString(),
            },
        }).promise();
    }
    
    function toUrlString(buffer) {
        return buffer.toString('base64')
            .replace(/\+/g, '-')
            .replace(/\//g, '_')
            .replace(/=/g, '');
    }
    
    function errorResponse(errorMessage, awsRequestId, callback) {
      callback(null, {
        statusCode: 500,
        body: JSON.stringify({
          Error: errorMessage,
          Reference: awsRequestId,
        }),
        headers: {
          'Access-Control-Allow-Origin': '*',
        },
      });
    }

        9. Scegli Implementa.

  • In questo modulo dovrai testare la funzione che hai creato usando la console AWS Lambda. Nel prossimo modulo, procederai con l'aggiunta di una REST API tramite Gateway API, in modo da poter chiamare la funzione dall'applicazione basata sul browser che hai distribuito nel primo modulo.

    1. Nella funzione RequestUnicorn che hai creato nella sezione precedente, scegli Test nella sezione Origine codice e seleziona Configura evento di test dal menu a discesa.
    2. Mantieni la selezione predefinita Crea nuovo evento.
    3. Specifica TestRequestEvent nel campo Nome evento.
    4. Copia e incolla il seguente evento test nella sezione JSON evento:
    {
        "path": "/ride",
        "httpMethod": "POST",
        "headers": {
            "Accept": "*/*",
            "Authorization": "eyJraWQiOiJLTzRVMWZs",
            "content-type": "application/json; charset=UTF-8"
        },
        "queryStringParameters": null,
        "pathParameters": null,
        "requestContext": {
            "authorizer": {
                "claims": {
                    "cognito:username": "the_username"
                }
            }
        },
        "body": "{\"PickupLocation\":{\"Latitude\":47.6174755835663,\"Longitude\":-122.28837066650185}}"
    }

        5. Scegli Salva.

        6. Nella sezione Origine codice della tua funzione, scegli Test e seleziona TestRequestEvent dal menu a discesa.

        7.  Nella scheda Test, scegli Test.

        8. Nel messaggio Executive function:succeeded che appare, espandi il menu a discesa Dettagli.

        9. Verifica che il risultato della funzione sia simile al seguente:

    {
        "statusCode": 201,
        "body": "{\"RideId\":\"SvLnijIAtg6inAFUBRT+Fg==\",\"Unicorn\":{\"Name\":\"Rocinante\",\"Color\":\"Yellow\",\"Gender\":\"Female\"},\"Eta\":\"30 seconds\"}",
        "headers": {
            "Access-Control-Allow-Origin": "*"
        }
    }

Questa pagina è stata utile?

Distribuzione di un'API RESTful