{"id":22433419,"url":"https://github.com/andresweitzel/appclientes_serverlessdynamodb","last_synced_at":"2025-03-27T07:45:43.889Z","repository":{"id":63062249,"uuid":"559393088","full_name":"andresWeitzel/AppClientes_ServerlessDynamoDB","owner":"andresWeitzel","description":"App para la gestión de clientes implementando NodeJs, Serverless V3, AWS CLI , SSM, Api Gateway, DynamoDB y Otras Tecnologías","archived":false,"fork":false,"pushed_at":"2023-02-05T16:47:53.000Z","size":43895,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-01T12:46:25.515Z","etag":null,"topics":["api-gateway","aws-cli","dynamodb","git","iam","lambdas","nodejs","serverless-framework","ssm","vscode"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/andresWeitzel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-10-30T01:01:39.000Z","updated_at":"2022-11-12T01:39:10.000Z","dependencies_parsed_at":"2023-02-15T14:01:33.309Z","dependency_job_id":null,"html_url":"https://github.com/andresWeitzel/AppClientes_ServerlessDynamoDB","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andresWeitzel%2FAppClientes_ServerlessDynamoDB","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andresWeitzel%2FAppClientes_ServerlessDynamoDB/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andresWeitzel%2FAppClientes_ServerlessDynamoDB/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andresWeitzel%2FAppClientes_ServerlessDynamoDB/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/andresWeitzel","download_url":"https://codeload.github.com/andresWeitzel/AppClientes_ServerlessDynamoDB/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245806387,"owners_count":20675296,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api-gateway","aws-cli","dynamodb","git","iam","lambdas","nodejs","serverless-framework","ssm","vscode"],"created_at":"2024-12-05T22:14:52.452Z","updated_at":"2025-03-27T07:45:43.872Z","avatar_url":"https://github.com/andresWeitzel.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# AppClientes_ServerlessDynamoDB\n\nApp para la gestión de clientes implementando NodeJs, Serverless V3, AWS CLI, SSM, Api Gateway, DynamoDB y Otras Tecnologías.\n\n\n\u003cbr\u003e\n\n## Índice 📜\n\n\u003cdetails\u003e\n \u003csummary\u003e Ver \u003c/summary\u003e\n \n \u003cbr\u003e\n \n### Sección 1) Descripción, Tecnologías y Dependencias \n\n - [1.0) Descripción del Proyecto.](#10-descripción-)\n - [1.1) Ejecución del Proyecto.](#11-ejecución-del-proyecto-)\n - [1.2) Tecnologías.](#12-tecnologías-)\n - [1.3) Plugins.](#13-plugins-)\n - [1.4) Extensiones VSC.](#14-extensiones-vsc-)\n \n \n### Sección 2) Proyecto Serverless desde cero \n \n - [2.0) Instalación y Configuración de Serverless Local](#20-instalación-y-configuración-de-serverless-local-)\n - [2.1) Configuración de Api Gateway](#21-configuración-de-api-gateway-) \n - [2.2) Ejecución de Serverless Local](#22-ejecución-de-serverless-local-)\n - [2.3) SSM y IAM](#23-ssm-y-iam-)\n      - [2.3.0) Arquitectura Lambda Function y SSM](#230-arquitectura-lambda-function-y-ssm)\n      - [2.3.1) Instalación y Configuración de SSM Local](#231-instalación-y-configuración-de-ssm-local-)\n \n \n ### Sección 3) DynamoDB\n \n - [3.0) Arquitectura Lambda, Api Gateway y DynamoDB](#30-arquitectura-lambda-api-gateway-y-dynamodb-)\n - [3.1) Instalación y Configuración de DynamoDB Local](#31-instalación-y-configuración-de-dynamodb-local-)\n - [3.2) Ejecución de DynamoDB Local](#32-ejecución-de-dynamodb-local-)\n\n\u003cbr\u003e\n\n\u003c/details\u003e\n\n\n\n\n\n\n\n\n\n\u003cbr\u003e\n\n## Sección 1) Descripción, Tecnologías y Dependencias \n\n\n### 1.0) Descripción [🔝](#índice-) \n\n\u003cdetails\u003e\n  \u003csummary\u003eVer\u003c/summary\u003e\n \n \u003cbr\u003e\n\n* ipsum\n\n\u003cbr\u003e\n\n\u003c/details\u003e\n\n\n### 1.1) Ejecución del Proyecto [🔝](#índice-)\n\n\u003cdetails\u003e\n  \u003csummary\u003eVer\u003c/summary\u003e\n  \n* Crear un entorno de trabajo a través de algún IDE\n* Clonar el Proyecto (`git clone https://github.com/andresWeitzel/AppClientes_ServerlessDynamoDB`)\n* Dentro del directorio instalar todos los plugins implementados\n  * `npm install serverless-offline --save-dev`\n  * `npm install -g serverless`\n  * `pip install awscli` \n  * `npm install serverless-offline-ssm --save-dev`\n  * `npm install serverless-dynamodb-local --save`\n  * `serverless dynamodb install`\n  * `serverless dynamodb start --migrate`\n  * Reiniciar el IDE caso de tenerlo ejecutado. \n* Levantar Serverless en Local (`sls offline start`)\n* Comprobar respuestas de los endpoints generados a través de alguna herramienta Cliente Http (Ej:Postman)\n\n\u003cbr\u003e\n\n\u003c/details\u003e\n\n\n### 1.2) Tecnologías [🔝](#índice-)\n\n\u003cdetails\u003e\n  \u003csummary\u003eVer\u003c/summary\u003e\n \n \u003cbr\u003e\n\n### Tecnologías Implementadas\n\n| **Tecnologías** | **Versión** | **Finalidad** |               \n| ------------- | ------------- | ------------- |\n| SDK | 4.3.2  | Inyección Automática de Módulas para Lambdas |\n| Serverless Framework Core | 3.23.0 | Core Servicios AWS |\n| Serverless Plugin | 6.2.2  | Librerías para la Definición Modular |\n| AWS CLI | 1.27.8 | Interfaz de línea de comandos unificada para Amazon Web Servicios. |\n| Systems Manager Parameter Store (SSM) | 3.0 | Manejo de Variables de Entorno |\n| Amazon Api Gateway | 2.0 | Gestor, Autenticación, Control y Procesamiento de la Api | \n| DynamoDB | - | SGDB NoSQL | \n| NodeJS | 14.18.1  | Librería JS |\n| VSC | 1.72.2  | IDE |\n| Postman| 10.11  | Cliente Http |\n| CMD | 10 | Símbolo del Sistema para linea de comandos | \n| Git | 2.29.1  | Control de Versiones |\n\n\u003cbr\u003e\n\n\u003c/details\u003e\n\n\n### 1.3) Plugins [🔝](#índice-)\n\n\u003cdetails\u003e\n  \u003csummary\u003eVer\u003c/summary\u003e\n\n| **Plugin** | **Descarga** |               \n| -------------  | ------------- |\n| serverless-offline |  https://www.serverless.com/plugins/serverless-offline |\n| serverless-offline-ssm |  https://www.npmjs.com/package/serverless-offline-ssm |\n| serverless-dynamodb-local |  https://www.npmjs.com/package/serverless-dynamodb-local |\n| awscli | https://pypi.org/project/awscli/ |\n\n\u003cbr\u003e\n\n\u003c/details\u003e\n\n### 1.4) Extensiones VSC [🔝](#índice-)\n\n\u003cdetails\u003e\n \u003csummary\u003eVer\u003c/summary\u003e\n\n| **Extensión** |              \n| -------------  | \n| Prettier - Code formatter |\n| YAML - Autoformatter .yml (alt+shift+f) |\n| DotENV |\n\n\n\u003cbr\u003e\n\n\u003c/details\u003e\n\n\n\u003cbr\u003e\n\n## Sección 2) Proyecto Serverless desde cero\n\n### Arquitectura Lambda Function y Api gateway \n\n\u003cdetails\u003e\n  \u003csummary\u003eVer\u003c/summary\u003e\n \n \n \u003cbr\u003e\n \n\u003cimg src=\"./doc/lambdasApiGateway.png\" style=\"width: 70%; height: 70%\"/\u003e\n\n\u003cbr\u003e\n\n\u003c/details\u003e\n\n\n### 2.0) Instalación y Configuración de Serverless Local [🔝](#índice-)\n\n\u003cdetails\u003e\n \u003csummary\u003eVer\u003c/summary\u003e\n \n \u003cbr\u003e\n\n* Una vez abierto el proyecto instalamos  serverless de forma Global `npm install -g serverless`\n* Seguidamente creamos toda la config de serverless para nuestro proyecto(en mi caso el nombre del proyecto es `project-dynamodb`) `serverless create --template aws-nodejs --path project-dynamodb \u0026\u0026 cd project-dynamodb`\n* Luego inicializamos el package.json en el proyecto `npm init -y`.\n* Instalamos el plugin serverless-offline `npm i serverless-offline`\n* Comprobamos versión `serverless --version`\n* Salida Esperada ..\n\n   ``` bash\n    Framework Core: 3.23.0\n    Plugin: 6.2.2\n    SDK: 4.3.2\n\n   ```\n* Agregamos el plugin instalado de serverless-offline al archivo `serverless.yml`\n* Configuramos los diversos parámetros necesarios del provider\n* Creamos el directorio `src/lambdas/` y todas las funciones lambdas las trabajaremos dentro del mismo\n* Cambiamos el nombre de nuestra lambda `handler.js` por `hello.js` y la llevamos al directorio de lambdas\n* Nuestra lambda quedaría....\n  ``` js\n   'use strict';\n\n   module.exports.test = async (event) =\u003e {\n     return {\n       statusCode: 200,\n       body: JSON.stringify(\n         {\n           message: 'HI, LAMBDA ACTIVE',\n           input: event,\n         },\n         null,\n         2\n       ),\n     };\n\n   };\n\n  ```\n* Configuramos tipo de método y path a través de httpApi para la lambda.\n* Configuramos el puerto http \n* Archivo serveless.yml..\n\n  ``` yml\n  \n   service: project-dynamodb\n\n   frameworkVersion: '3'\n\n   provider:\n     name: aws\n     runtime: nodejs14.x\n     stage: dev\n     region : us-west-1\n     memorySize: 512\n     timeout : 20\n\n   plugins:\n     - serverless-offline \n\n   custom: \n     serverless-offline:\n       httpPort: 4000   \n\n   functions:\n     hello:\n       handler: src/lambdas/hello.test\n       events:\n         - httpApi:\n             method: GET\n             path: hello\n\n  ``` \n   \n  \n\u003c/br\u003e   \n\n* Guía Oficial : https://www.serverless.com//blog/serverless-framework-v3-is-live)   \n* Guía Recomendada : https://medium.com/@patricio.aranguiz/serverless-offline-aws-lambda-api-gateway-15a4dfdfbc16\n* Config Parámetros Provider : https://www.tutorialspoint.com/serverless/serverless_regions_memory_size_timeouts.htm\n\n\n\u003cbr\u003e\n \n\u003c/details\u003e\n\n\n### 2.1) Configuración de Api Gateway [🔝](#índice-) \n\n\u003cdetails\u003e\n \u003csummary\u003eVer\u003c/summary\u003e\n \n \u003cbr\u003e\n \n \n * API Gateway gestiona todas las tareas relacionadas con la aceptación y el procesamiento de centenares de miles de llamadas simultáneas a la API. Estas tareas incluyen la administración del tráfico, el control de la autorización y el acceso, el monitoreo y la administración de versiones de la API.\n* No es necesario la instalación de ningún paquete adicional, este servicio viene incluido en la instalación principal de serverless.\n* Para cada lambda es necesario adicionar el parametro `private: true` dentro de `- httpApi` para que se aplique la restricción de acceso correctamente.\n* Vamos a generar una sección de `resources` . Esta es la plantilla de CloudFormation (Servicio de recursos de AWS) para declarar los recursos de serverless a utilizar.\n* En este caso vamos a extender los diversos manejos de recursos para nuestra Api Gateway. (Tipos, Templates y Códigos de Respuesta).\n* Para desacoplar código de nuestro serverless.yml para a generar un archivo .yml aparte para nuestro api gateway.\n* Creamos dicho archivo dentro de la siguiente jerarquia dentro de nuestro proyecto `src/resources/api-gateway.yml`\n* Nuestro `api-gateway.yml` quedaría..\n\n  ``` yml\n   Resources:\n      ApiGatewayRestApi:\n      Type: AWS::ApiGateway::RestApi\n      Properties:\n        Name: apiGatewayRestApi\n      #### Gateway Response INIT\n    GatewayResponseDefault400:\n      Type: \"AWS::ApiGateway::GatewayResponse\"\n      Properties:\n        RestApiId:\n          Ref: \"ApiGatewayRestApi\"\n        ResponseType: DEFAULT_4XX\n        ResponseTemplates:\n          application/json: '{\"error\":{\"code\":\"custom-4XX-generic\",\"message\":$context.error.messageString},\"requestId\":\"$context.requestId\"}'\n    GatewayResponseDefault500:\n      Type: \"AWS::ApiGateway::GatewayResponse\"\n      Properties:\n        RestApiId:\n          Ref: \"ApiGatewayRestApi\"\n        ResponseType: DEFAULT_5XX\n        ResponseTemplates:\n          application/json: '{\"error\":{\"code\":\"custom-5XX-generic\",\"message\":$context.error.messageString},\"requestId\":\"$context.requestId\"}'\n    GatewayResponseAccessDeied:\n      Type: \"AWS::ApiGateway::GatewayResponse\"\n      Properties:\n        RestApiId:\n          Ref: \"ApiGatewayRestApi\"\n        ResponseType: ACCESS_DENIED\n        ResponseTemplates:\n          application/json: '{\"error\":{\"code\":\"custom-403-access-denied\",\"message\":$context.error.messageString},\"requestId\":\"$context.requestId\"}'\n    GatewayResponseApiConfigurationError:\n      Type: \"AWS::ApiGateway::GatewayResponse\"\n      Properties:\n        RestApiId:\n          Ref: \"ApiGatewayRestApi\"\n        ResponseType: API_CONFIGURATION_ERROR\n        ResponseTemplates:\n          application/json: '{\"error\":{\"code\":\"custom-500-api-configuration-error\",\"message\":$context.error.messageString},\"requestId\":\"$context.requestId\"}'\n    GatewayResponseAuthorizerConfigurationError:\n      Type: \"AWS::ApiGateway::GatewayResponse\"\n      Properties:\n        RestApiId:\n          Ref: \"ApiGatewayRestApi\"\n        ResponseType: AUTHORIZER_CONFIGURATION_ERROR\n        ResponseTemplates:\n          application/json: '{\"error\":{\"code\":\"custom-500-authorizer-configuration-error\",\"message\":$context.error.messageString},\"requestId\":\"$context.requestId\"}'\n    GatewayResponseAuthorizerFailure:\n      Type: \"AWS::ApiGateway::GatewayResponse\"\n      Properties:\n        RestApiId:\n          Ref: \"ApiGatewayRestApi\"\n        ResponseType: AUTHORIZER_FAILURE\n        ResponseTemplates:\n          application/json: '{\"error\":{\"code\":\"custom-500-authorizer-failure\",\"message\":$context.error.messageString},\"requestId\":\"$context.requestId\"}'\n    GatewayResponseBadRequestBody:\n      Type: \"AWS::ApiGateway::GatewayResponse\"\n      Properties:\n        RestApiId:\n          Ref: \"ApiGatewayRestApi\"\n        ResponseType: BAD_REQUEST_BODY\n        ResponseTemplates:\n          application/json: '{\"error\":{\"code\":\"custom-400-bad-request-body\",\"message\":$context.error.messageString},\"requestId\":\"$context.requestId\"}'\n    GatewayResponseBadRequestParameters:\n      Type: \"AWS::ApiGateway::GatewayResponse\"\n      Properties:\n        RestApiId:\n          Ref: \"ApiGatewayRestApi\"\n        ResponseType: BAD_REQUEST_PARAMETERS\n        ResponseTemplates:\n          application/json: '{\"error\":{\"code\":\"custom-400-bad-request-parameters\",\"message\":$context.error.messageString},\"requestId\":\"$context.requestId\"}'\n    GatewayResponseExpiredToken:\n      Type: \"AWS::ApiGateway::GatewayResponse\"\n      Properties:\n        RestApiId:\n          Ref: \"ApiGatewayRestApi\"\n        ResponseType: EXPIRED_TOKEN\n        ResponseTemplates:\n          application/json: '{\"error\":{\"code\":\"custom-403-expired-token\",\"message\":$context.error.messageString},\"requestId\":\"$context.requestId\"}'\n    GatewayResponseIntegrationFailure:\n      Type: \"AWS::ApiGateway::GatewayResponse\"\n      Properties:\n        RestApiId:\n          Ref: \"ApiGatewayRestApi\"\n        ResponseType: INTEGRATION_FAILURE\n        ResponseTemplates:\n          application/json: '{\"error\":{\"code\":\"custom-504-integration-failure\",\"message\":$context.error.messageString},\"requestId\":\"$context.requestId\"}'\n    GatewayResponseIntegrationTimeout:\n      Type: \"AWS::ApiGateway::GatewayResponse\"\n      Properties:\n        RestApiId:\n          Ref: \"ApiGatewayRestApi\"\n        ResponseType: INTEGRATION_TIMEOUT\n        ResponseTemplates:\n          application/json: '{\"error\":{\"code\":\"custom-504-integration-timeout\",\"message\":$context.error.messageString},\"requestId\":\"$context.requestId\"}'\n    GatewayResponseInvalidApiKey:\n      Type: \"AWS::ApiGateway::GatewayResponse\"\n      Properties:\n        RestApiId:\n          Ref: \"ApiGatewayRestApi\"\n        ResponseType: INVALID_API_KEY\n        ResponseTemplates:\n          application/json: '{\"error\":{\"code\":\"custom-403-invalid-api-key\",\"message\":$context.error.messageString},\"requestId\":\"$context.requestId\"}'\n    GatewayResponseInvalidSignature:\n      Type: \"AWS::ApiGateway::GatewayResponse\"\n      Properties:\n        RestApiId:\n          Ref: \"ApiGatewayRestApi\"\n        ResponseType: INVALID_SIGNATURE\n        ResponseTemplates:\n          application/json: '{\"error\":{\"code\":\"custom-403-invalid-signature\",\"message\":$context.error.messageString},\"requestId\":\"$context.requestId\"}'\n    GatewayResponseMissingAuthenticationToken:\n      Type: \"AWS::ApiGateway::GatewayResponse\"\n      Properties:\n        RestApiId:\n          Ref: \"ApiGatewayRestApi\"\n        ResponseType: MISSING_AUTHENTICATION_TOKEN\n        ResponseTemplates:\n          application/json: '{\"error\":{\"code\":\"custom-403-missing-authentication-token\",\"message\":$context.error.messageString},\"requestId\":\"$context.requestId\"}'\n    GatewayResponseQuotaExceeded:\n      Type: \"AWS::ApiGateway::GatewayResponse\"\n      Properties:\n        RestApiId:\n          Ref: \"ApiGatewayRestApi\"\n        ResponseType: QUOTA_EXCEEDED\n        ResponseTemplates:\n          application/json: '{\"error\":{\"code\":\"custom-429-quota-exceeded\",\"message\":$context.error.messageString},\"requestId\":\"$context.requestId\"}'\n    GatewayResponseRequestTooLarge:\n      Type: \"AWS::ApiGateway::GatewayResponse\"\n      Properties:\n        RestApiId:\n          Ref: \"ApiGatewayRestApi\"\n        ResponseType: REQUEST_TOO_LARGE\n        ResponseTemplates:\n          application/json: '{\"error\":{\"code\":\"custom-413-request-too-large\",\"message\":$context.error.messageString},\"requestId\":\"$context.requestId\"}'\n    GatewayResponseResourceNotFound:\n      Type: \"AWS::ApiGateway::GatewayResponse\"\n      Properties:\n        RestApiId:\n          Ref: \"ApiGatewayRestApi\"\n        ResponseType: RESOURCE_NOT_FOUND\n        ResponseTemplates:\n          application/json: '{\"error\":{\"code\":\"custom-404-resource-not-found\",\"message\":$context.error.messageString},\"requestId\":\"$context.requestId\"}'\n    GatewayResponseThrottled:\n      Type: \"AWS::ApiGateway::GatewayResponse\"\n      Properties:\n        RestApiId:\n          Ref: \"ApiGatewayRestApi\"\n        ResponseType: THROTTLED\n        ResponseTemplates:\n          application/json: '{\"error\":{\"code\":\"custom-429-throttled\",\"message\":$context.error.messageString},\"requestId\":\"$context.requestId\"}'\n    GatewayResponseUnauthorized:\n      Type: \"AWS::ApiGateway::GatewayResponse\"\n      Properties:\n        RestApiId:\n          Ref: \"ApiGatewayRestApi\"\n        ResponseType: UNAUTHORIZED\n        ResponseTemplates:\n          application/json: '{\"error\":{\"code\":\"custom-401-unauthorized\",\"message\":$context.error.messageString},\"requestId\":\"$context.requestId\"}'\n    GatewayResponseUnauthorizedMediType:\n      Type: \"AWS::ApiGateway::GatewayResponse\"\n      Properties:\n        RestApiId:\n          Ref: \"ApiGatewayRestApi\"\n        ResponseType: UNSUPPORTED_MEDIA_TYPE\n        ResponseTemplates:\n          application/json: '{\"error\":{\"code\":\"custom-415-unsupported-media-type\",\"message\":$context.error.messageString},\"requestId\":\"$context.requestId\"}'\n      #### Gateway Response END\n\n  ``` \n* Seguidamente referenciamos el archivo `api-gateway.yml` al `serverless.yml`\n* La configuración General de nuestro `serverless.yml` quedaría...\n\n     ``` yml\n  \n   service: project-dynamodb\n\n   frameworkVersion: \"3\"\n\n   provider:\n     name: aws\n     runtime: nodejs14.x\n     stage: dev\n     region : us-west-1\n     memorySize: 512\n     timeout : 10\n\n   plugins:\n     - serverless-offline\n\n   custom:\n     serverless-offline:\n       httpPort: 4000\n\n   functions:\n     hello:\n       handler: src/lambdas/hello.test\n       events:\n         - httpApi:\n             method: GET\n             path: hello\n             private: true\n\n   resources:\n     - ${file(src/resources/api-gateway.yml)}\n\n  ```\n\n\u003c/br\u003e   \n\n* [Código Base de Ejemplo](https://gist.github.com/jonatassaraiva/4c33dd8225605c02318cd71a55b2335d)\n\n\n\n\u003cbr\u003e\n\n\u003c/details\u003e\n \n\n\n\n\n### 2.2) Ejecución de Serverless Local [🔝](#índice-)\n\n\u003cdetails\u003e\n \u003csummary\u003eVer\u003c/summary\u003e\n \n \u003cbr\u003e\n\n\n* Por defecto tenemos configurado una lambda llamada hello a través de su función .test que se ha modificado( por defecto serverless crea una lambda handler.js)\n* Además tenemos configurada la seguridad y manejo de responses por parte de la Api Gateway, esta nos provera un token de acceso (x-api-key) para el acceso a cada lambda.\n* Levantamos serverless con el comando `sls offline start` o `serverless offline start`\n* Visualizamos el endpoint local que serverless nos genera..\n\n     ``` bash\n     Starting Offline at stage dev (us-east-1)\n\n   Offline [http for lambda] listening on http://localhost:3002\n   Function names exposed for local invocation by aws-sdk:\n              * hello: project-dynamodb-dev-hello\n   Remember to use 'x-api-key' on the request headers.\n   Key with token: 'd41d8cd98f00b204e9800998ecf8427e'           \n              \n    GET | http://localhost:3000/hello   \n    POST | http://localhost:3000/2015-03-31/functions/hello/invocations \n    \n    Server ready: http://localhost:4000\n  ``` \n* Abrimos alguna herramienta para generar peticiones http (ej: Postman) y generamos una request al endpoint generado junto con la api key de nuestro gateway  \n* Seleccionamos método `GET`, luego escribimos el endpoint `http://localhost:3000/hello`, seguidamente pestaña `Headers` en `KEY` colocamos `x-api-key` y en `VALUE` colocamos el token generado `d41d8cd98f00b204e9800998ecf8427e`.\n* Procedemos a ejecutar la request y podemos comprobar la metadata de la lambda en la consola de postman\n* También obtenemos la respuesta por consola..\n  \n  ``` bash\n    GET /hello (λ: hello)\n   (λ: hello) RequestId: 63fc1719-ae56-4d56-8296-87d45b44fc96  Duration: 124.64 ms  Billed Duration: 125 ms\n  ```\n  \n  \n\u003cbr\u003e\n\n\u003c/details\u003e\n \n\n\n\n### 2.3) SSM e IAM [🔝](#índice-)\n\n### 2.3.0) Arquitectura Lambda Function y SSM \n\n\u003cdetails\u003e\n \u003csummary\u003eVer\u003c/summary\u003e\n \n\u003cbr\u003e\n \n\u003cimg src=\"./doc/ssmLambdas.png\" style=\"width: 70%; height: 70%\"/\u003e\n\n\u003cbr\u003e\n\n\u003c/details\u003e\n\n\n### 2.3.1) Instalación y Configuración de SSM Local [🔝](#índice-)\n\n\n\u003cdetails\u003e\n \u003csummary\u003eVer\u003c/summary\u003e\n \n \u003cbr\u003e\n\n* Instalamos el plugin `npm install serverless-offline serverless-offline-ssm --save-dev`\n* Agregamos el complemento dentro del serverless.yml. Es importante mantener el orden siguiente (serverless-offline siempre último por temas de compatibilidad).\n   \n  ``` YML\n    plugins:\n       - serverless-offline-ssm\n       - serverless-offline\n  ``` \n* Dentro del proyecto creamos el archivo `serverless.env.yml` que será el que contenga los valores de las variables de entorno de nuestro proyecto\n* Dentro de dicho archivo colocamos una variable test para comprobar su funcionamiento.. \n  \n  ``` YML\n    HELLO_TEST : ${ssm:/hello_test}  \n  ```\n* Relacionamos el arhivo `serverless.env.yml` dentro del `serverless.yml` agregando el parametro `enviroment` junto a dicho archivo..\n \n  ``` YML\n   provider:\n     name: aws\n     runtime: nodejs14.x\n     stage: dev\n     region : us-west-1\n     memorySize: 512\n     timeout : 10\n     environment: ${file(serverless.env.yml)}  \n  ``` \n* Seguidamente vamos a configurar el ssm dentro del bloque `custom` para el archivo `serverless.yml` \n* Agregamos el stage (IMPORTANTE RESPETAR EL STAGE DEL PROVIDER Y DEL SSM) y la variable test, quedando..\n\n  ``` YML\n    custom:\n     serverless-offline-ssm:\n       stages:\n         - dev\n       ssm:\n         '/hello_test': 'HELLO SSM'\n     serverless-offline:\n       httpPort: 4000  \n  ```\n* Por último utilizamos dicha variable en la lambda declarada, para invocar una variable de entorno utilizamos `process.env.variable`  \n \n    ```js\n      'use strict';\n\n      module.exports.test = async (event) =\u003e {\n        return {\n          statusCode: 200,\n          body: JSON.stringify(\n            {\n              message: process.env.HELLO_TEST,\n              input: event,\n            },\n            null,\n            2\n          ),\n        };\n\n      };\n\n   ```\n* Ejecutamos el programa, realizamos la petición get a través de postman a nuestra lambda y podemos visualizar la metadata de la misma junto con nuestra variable de entorno.\n* Salida Esperada..\n\n     ```cmd\n        {\n          \"message\": \"HELLO SSM\",\n          \"input\": {\n              \"body\": null,\n              \"cookies\": [],\n              \"headers\": {\n                  \"x-api-key\": \"d41d8cd98f00b204e9800998ecf8427e\",\n                  \"content-type\": \"application/json\",\n                  \"user-agent\": \"PostmanRuntime/7.29.2\",\n                  \"accept\": \"*/*\",\n                  \"cache-control\": \"no-cache\",\n                  \"postman-token\": \"ea2e186f-732f-450e-abf2-4572b3e0206b\",\n                  \"host\": \"localhost:4000\",\n                  \"accept-encoding\": \"gzip, deflate, br\",\n                  \"connection\": \"keep-alive\",\n                  \"content-length\": \"163\"\n              },\n              \"isBase64Encoded\": false,\n              \"pathParameters\": null,\n              \"queryStringParameters\": null,\n              \"rawPath\": \"/hello\",\n              \"rawQueryString\": \"\",\n              \"requestContext\": {\n                  \"accountId\": \"offlineContext_accountId\",\n                  \"apiId\": \"offlineContext_apiId\",\n                  \"authorizer\": {\n                      \"jwt\": {}\n                  },\n                  \"domainName\": \"offlineContext_domainName\",\n                  \"domainPrefix\": \"offlineContext_domainPrefix\",\n                  \"http\": {\n                      \"method\": \"GET\",\n                      \"path\": \"/hello\",\n                      \"protocol\": \"HTTP/1.1\",\n                      \"sourceIp\": \"127.0.0.1\",\n                      \"userAgent\": \"PostmanRuntime/7.29.2\"\n                  },\n                  \"requestId\": \"offlineContext_resourceId\",\n                  \"routeKey\": \"GET hello\",\n                  \"stage\": \"$default\",\n                  \"time\": \"31/Oct/2022:23:49:02 -0300\",\n                  \"timeEpoch\": 1667270942415\n              },\n              \"routeKey\": \"GET hello\",\n              \"stageVariables\": null,\n              \"version\": \"2.0\"\n          }\n      }\n    ```\n  \n  \u003cbr\u003e\n\n\u003c/details\u003e\n\n\n\u003cbr\u003e\n\n\n## Sección 3) DynamoDB\n\n\n### 3.0) Arquitectura Lambda, Api Gateway y DynamoDB [🔝](#índice-)\n\n\u003cdetails\u003e\n \u003csummary\u003eVer\u003c/summary\u003e\n \n \u003cbr\u003e\n \n ![Index app](./doc/lambdasDynamo.png)\n \n \u003cbr\u003e\n\n\u003c/details\u003e\n\n\n\n### 3.1) Instalación y Configuración de DynamoDB Local [🔝](#índice-)\n\n\u003cdetails\u003e\n \u003csummary\u003eVer\u003c/summary\u003e\n \n \u003cbr\u003e\n\n * Dentro del directorio del proyecto ejecutamos `npm i serverless-dynamodb-local --save`\n* Agregamos el plugin en el .yml\n\n   ```yml\n      plugins:\n         - serverless-dynamodb-local\n   ```\n\n* Luego instalamos los complementos de dynamo `serverless dynamodb install`\n* Dentro de `src/resources/` creamos el archivo `dynamo-table.yml`.\n* Agregamos la config de la db (tablas, propiedades, etc) dentro de dicho .yml.\n* Nuestro archivo `dynamo-table.yml` quedaría....\n   \n   ```yml\n    Resources:\n     usersTable:\n       Type: AWS::DynamoDB::Table\n       Properties:\n         TableName: usersTable\n         AttributeDefinitions:\n           - AttributeName: year\n             AttributeType: N\n           - AttributeName: title\n             AttributeType: S\n         KeySchema:\n           - AttributeName: year\n             KeyType: HASH\n           - AttributeName: title\n             KeyType: RANGE\n         ProvisionedThroughput:\n           ReadCapacityUnits: 10\n           WriteCapacityUnits: 10\n\n   ```\n* Agregamos dicho archivo al `serverless.yml` en la sección de resources..\n\n  ```yml\n   resources:\n      - ${file(src/resources/api-gateway.yml)}\n      - ${file(src/resources/dynamo-table.yml)}\n\n  ```\n\n* Verificamos que Dynamo haya sido configurado correctamente, ejecutamos dicho sgdb... `serverless dynamodb start --migrate`\n* Salida esperada..\n\n   ```cmd\n    Dynamodb Local Started, Visit: http://localhost:8000/shell\n    DynamoDB - created table usersTable\n   \n   ```\n\n \u003cbr\u003e\n\n\u003c/details\u003e\n  \n\n### 3.2) Ejecución de DynamoDB Local [🔝](#índice-)\n\n\u003cdetails\u003e\n \u003csummary\u003eVer\u003c/summary\u003e\n \n \u003cbr\u003e\n\n * Para poder visualizar nuestro esquema de tablas y datos en local debemos utilizar `aws cli`.\n* Instalamos dicho paquete `pip install awscli`\n* Comprobamos la versión `aws --version`\n* Salida Esperada...\n \n  ```cmd\n    aws-cli/1.27.8 Python/3.9.5 Windows/10 botocore/1.29.8\n  ```\n* Configuramos `credenciales ficticias`. DynamoDB offline no las validará, solo hay que proporcionarlas, no puede estar en blanco.\n* `export AWS_ACCESS_KEY_ID=223344`\n* `export AWS_SECRET_ACCESS_KEY=wJalrXUtTHISI/DYNAMODB/bPxRfiCYEXAMPLEKEY`\n* Seguidamente en otra bash/terminal levantamos Dynamodb `serverless dynamodb start --migrate`\n* Salida esperada..\n\n   ```cmd\n    Dynamodb Local Started, Visit: http://localhost:8000/shell\n    DynamoDB - created table usersTable\n   \n   ```\n* Regresando a la consola anterior levantamos aws cli con el endpoint que se nos ha generado (http://localhost:8000) y pasandole la región.\n* Ejecutamos `aws dynamodb list-tables --endpoint-url http://localhost:8000 --region=us-east-1`\n* Salida Esperada..\n  \n   ```cmd\n       {\n        \"TableNames\": [\n            \"usersTable\"\n        ]\n    }\n   \n   ```\n* `Hemos creado, configurado y ejecutado correctamente lo básico para poder trabajar con DynamoDB`\n\n\u003c/br\u003e\n\n* https://dynobase.dev/run-dynamodb-locally/#serverless-framework\n* https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-dynamo-db.html\n* https://dynobase.dev/run-dynamodb-locally/#connecting-dynamodb-offline-cli\n\n* CRUD DynamoDB : https://medium.com/dev-jam/serverless-simple-crud-application-in-10-minutes-on-aws-69e022298e80\n* ÚLTIMA DOC IMPLEMENTADA CRUD DynamoDB : https://dev.to/rajandmr/dynamodb-crud-with-nodejs-and-lambda-inn\n\n \n \n \u003cbr\u003e\n\n\u003c/details\u003e\n\n\n\n\n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandresweitzel%2Fappclientes_serverlessdynamodb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandresweitzel%2Fappclientes_serverlessdynamodb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandresweitzel%2Fappclientes_serverlessdynamodb/lists"}