Cet article est un article pratique pour passer en revue et établir les connaissances acquises en développant Serverless Web App Mosaic C'est l'un des w2or3w / items / 87b57dfdbcf218de91e2).
Ce serait bien de lire cet article après avoir regardé ce qui suit.
Une API appelée AppSync est utilisée pour la gestion des données des images téléchargées et des images traitées, ainsi que pour le transfert de données côté client. DynamoDB est utilisé comme source de données pour AppSync. AppSync peut également être configuré avec la CLI Amplify, mais je ne semblais pas être en mesure de spécifier la clé de partition DynanoDB ou la clé de tri, donc je n'utilise pas la CLI Amplify. Créez DynamoDB et AppSync dans la console AWS. Requête de Vue sur le front-end en utilisant Amplify, et de Lambda (Python) sur le back-end par HTTP.
Je peux configurer AppSync avec la CLI Amplify, mais il semble que je ne puisse pas spécifier la clé de partition et la clé de tri de DynamoDB. Je pourrais peut-être le faire, mais je ne savais pas comment le faire. Si quelqu'un sait, faites-le moi savoir. Donc, c'est un peu plus gênant que la ligne de commande, mais faisons-le avec la console AWS.
Créez d'abord DynamoDB comme source de données pour AppSync. AWS Console> DynamoDB> Créer une table Créez un tableau avec les paramètres suivants. Nom de la table: sample_appsync_table Clé de partition: groupe (chaîne de caractères) Clé de tri: chemin (chaîne de caractères)
Une fois DynamoDB créé, il est temps de créer AppSync. AWS Console> AppSync> Créer une API
Étape 1: Premiers pas Sélectionnez "Importer la table DynamoDB" et appuyez sur le bouton "Démarrer". ![Capture d'écran 2020-01-02 à 23.36.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394775/0d34eb39-937e-1b41-215e- 5216cc8228dc.png) Étape 2: créer un modèle Sélectionnez la table que vous avez créée précédemment (sample_appsync_table). Sélectionnez "Nouveau rôle" dans "Créer ou utiliser un rôle existant". Appuyez sur le bouton "Importer". Appuyez simplement sur le bouton "Créer". Étape 3: créer une ressource Définissez le nom de l'API et appuyez sur le bouton "Créer".
AWS Console> AppSync> sample_appsync_table> Dans le menu Schéma
Téléchargez schema.json
. Ce fichier est utilisé dans l'application Web.
AWS Console> AppSync> sample_appsync_table> Dans le menu des paramètres
Vérifiez les informations de ʻAPI URL et ʻAPI KEY
dans API Detail. Ces informations seront utilisées dans l'application.
Laissez le mode d'authentification comme "clé API". La date d'expiration de la clé API est de 7 jours par défaut, mais vous pouvez la prolonger jusqu'à 365 jours en la modifiant. J'écrirai un autre article sur la façon d'utiliser le mode d'authentification en tant qu'utilisateur Cognito comme Storage.
Après avoir configuré AppSync, continuez à mettre à jour l'application Web.
Créez un dossier src / graphql et ajoutez trois fichiers.
src/graphql/schema.json
Ajoutez le fichier téléchargé au projet tel quel.
src/graphql/queries.js
export const listSampleAppsyncTables = `query listSampleAppsyncTables($group: String) {
listSampleAppsyncTables(
limit: 1000000
filter: {
group: {eq:$group}
}
)
{
items
{
group
path
}
}
}
`;
Il s'agit d'une requête pour obtenir la liste des enregistrements en spécifiant le groupe de la clé de partition. C'est un mystère, mais si vous ne spécifiez pas la limite, vous ne pourrez pas obtenir les données. Je pense que c'est une spécification AppSync, pas graphql, mais qu'en est-il? J'ai spécifié un nombre raisonnablement élevé de 1000000, mais honnêtement, c'est trop subtil. Si quelqu'un connaît une meilleure façon d'écrire, faites-le moi savoir.
src/graphql/subscriptions.js
export const onCreateSampleAppsyncTable = `subscription OnCreateSampleAppsyncTable($group: String) {
onCreateSampleAppsyncTable(group : $group) {
group
path
}
}
`;
Il s'agit d'un abonnement pour spécifier le groupe de la clé de partition et pour être notifié avec les informations lorsque l'enregistrement est inséré. J'ai écrit "Lorsqu'un enregistrement est inséré", mais il n'est pas possible d'insérer un enregistrement directement dans DynamoDB, et il doit être inséré par create dans AppSync.
Ajoutez les informations requises pour accéder à AppSync dans src / aws-exports.js
.
src/aws-exports.js
const awsmobile = {
"aws_project_region": "ap-northeast-1",
"aws_cognito_identity_pool_id": "ap-northeast-1:********-****-****-****-************",
"aws_cognito_region": "ap-northeast-1",
"aws_user_pools_id": "ap-northeast-1_*********",
"aws_user_pools_web_client_id": "**************************",
"oauth": {},
"aws_user_files_s3_bucket": "sample-vue-project-bucket-work",
"aws_user_files_s3_bucket_region": "ap-northeast-1",
"aws_appsync_graphqlEndpoint": "https://**************************.appsync-api.ap-northeast-1.amazonaws.com/graphql",
"aws_appsync_region": "ap-northeast-1",
"aws_appsync_authenticationType": "API_KEY",
"aws_appsync_apiKey": "da2-**************************"
};
export default awsmobile;
Les informations contenues dans ce fichier sont importantes, veuillez donc les manipuler avec soin afin de ne pas les fuir.
Après avoir sélectionné une image dans Accueil et l'avoir téléchargée, implémentez une liste d'informations sur l'image téléchargée et l'image traitée monochrome à la destination de transition de page.
Ajoutez une page appelée Liste. Paramètres du routeur pour cela.
src/router.js
import Vue from 'vue';
import Router from 'vue-router';
import Home from './views/Home.vue';
import About from './views/About.vue';
import List from './views/List.vue';
Vue.use(Router);
export default new Router({
routes: [
{
path: '/',
name: 'home',
component: Home,
},
{
path: '/about',
name: 'about',
component: About,
},
{
path: '/list',
name: 'list',
component: List,
},
]
});
Vue de la page de liste
src/views/List.vue
<template>
<List />
</template>
<script>
import List from '../components/List'
export default {
components: {
List
}
}
</script>
Liste des composants de la page
src/components/List.vue
<template>
<v-container>
<p>liste</p>
<router-link to="/" >link to Home</router-link>
<hr>
<v-list>
<v-list-item v-for="data in this.dataList" :key="data.path">
<v-list-item-content>
<a :href="data.image" target=”_blank”>
<v-list-item-title v-text="data.path"></v-list-item-title>
</a>
</v-list-item-content>
<v-list-item-avatar>
<v-img :src="data.image"></v-img>
</v-list-item-avatar>
</v-list-item>
</v-list>
</v-container>
</template>
<script>
import { API, graphqlOperation, Storage } from 'aws-amplify';
import { listSampleAppsyncTables } from "../graphql/queries";
import { onCreateSampleAppsyncTable } from "../graphql/subscriptions";
const dataExpireSeconds = (30 * 60);
export default {
name: 'List',
data: () => ({
group: null,
dataList: [],
}),
mounted: async function() {
this.getList();
},
methods:{
async getList() {
this.group = this.$route.query.group;
console.log("group : " + this.group);
if(!this.group){
return;
}
let apiResult = await API.graphql(graphqlOperation(listSampleAppsyncTables, { group : this.group }));
let listAll = apiResult.data.listSampleAppsyncTables.items;
for(let data of listAll) {
let tmp = { path : data.path, image : "" };
let list = [...this.dataList, tmp];
this.dataList = list;
console.log("path : " + data.path);
Storage.get(data.path.replace('public/', ''), { expires: dataExpireSeconds }).then(result => {
tmp.image = result;
console.log("image : " + result);
}).catch(err => console.log(err));
}
API.graphql(
graphqlOperation(onCreateSampleAppsyncTable, { group : this.group } )
).subscribe({
next: (eventData) => {
let data = eventData.value.data.onCreateSampleAppsyncTable;
let tmp = { path : data.path, image : "" };
let list = [...this.dataList, tmp];
this.dataList = list;
console.log("path : " + data.path);
Storage.get(data.path.replace('public/', ''), { expires: dataExpireSeconds }).then(result => {
tmp.image = result;
console.log("image : " + result);
}).catch(err => console.log(err));
}
});
},
}
}
</script>
Obtenez le groupe dans le paramètre de requête. Lorsqu'elles sont montées avant l'affichage de l'écran, les données d'enregistrement sont acquises en spécifiant le groupe, ou les données d'enregistrement sont acquises lorsque l'événement d'insertion est reçu. Les données d'enregistrement acquises sont conservées dans un tableau de variables membres appelé dataList et affichées côte à côte dans v-list à l'écran. Dans v-list, le chemin et l'image des données d'enregistrement sont affichés. On accède à l'image en obtenant l'adresse avec la date d'expiration (30 minutes) avec Strage.
src/components/Home.vue
<template>
<v-container>
<p>domicile</p>
<router-link to="about" >link to About</router-link>
<hr>
<v-btn @click="selectFile">
SELECT A FILE !!
</v-btn>
<input style="display: none"
ref="input" type="file"
@change="uploadSelectedFile()">
</v-container>
</template>
<script>
import Vue from 'vue'
import { Auth, Storage } from 'aws-amplify';
export default {
name: 'Home',
data: () => ({
loginid: "sample-vue-project-user",
loginpw: "sample-vue-project-user",
}),
mounted: async function() {
this.login();
},
methods:{
login() {
console.log("login.");
Auth.signIn(this.loginid, this.loginpw)
.then((data) => {
if(data.challengeName == "NEW_PASSWORD_REQUIRED"){
console.log("new password required.");
data.completeNewPasswordChallenge(this.loginpw, {},
{
onSuccess(result) {
console.log("onSuccess");
console.log(result);
},
onFailure(err) {
console.log("onFailure");
console.log(err);
}
}
);
}
console.log("login successfully.");
}).catch((err) => {
console.log("login failed.");
console.log(err);
});
},
selectFile() {
if(this.$refs.input != undefined){
this.$refs.input.click();
}
},
uploadSelectedFile() {
let file = this.$refs.input.files[0];
if(file == undefined){
return;
}
console.log(file);
let dt = new Date();
let dirName = this.getDirString(dt);
let filePath = dirName + "/" + file.name;
Storage.put(filePath, file).then(result => {
console.log(result);
}).catch(err => console.log(err));
this.$router.push({ path: 'list', query: { group: dirName }});
},
getDirString(date){
let random = date.getTime() + Math.floor(100000 * Math.random());
random = Math.random() * random;
random = Math.floor(random).toString(16);
return "" +
("00" + date.getUTCFullYear()).slice(-2) +
("00" + (date.getMonth() + 1)).slice(-2) +
("00" + date.getUTCDate()).slice(-2) +
("00" + date.getUTCHours()).slice(-2) +
("00" + date.getUTCMinutes()).slice(-2) +
("00" + date.getUTCSeconds()).slice(-2) +
"-" + random;
},
}
}
</script>
Utilisez uploadSelectedFile pour accéder à la page Liste après le téléchargement du fichier. À ce moment-là, un paramètre de requête appelé groupe est attaché.
Ceci termine la réparation du serveur frontal (application Web), mais le contrôle du fonctionnement est effectué une fois le côté arrière terminé.
Mettre en œuvre pour insérer un enregistrement d'un fichier téléchargé depuis une application Web ou un chemin d'image monochrome (clé S3) généré et téléchargé par Lambda via AppSync.
Installez gql.
pip install gql -t .
Mettez à jour lambda_function.py
comme suit:
lambda_function.py
# coding: UTF-8
import boto3
import os
from urllib.parse import unquote_plus
import numpy as np
import cv2
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
s3 = boto3.client("s3")
from gql import gql, Client
from gql.transport.requests import RequestsHTTPTransport
ENDPOINT = "https://**************************.appsync-api.ap-northeast-1.amazonaws.com/graphql"
API_KEY = "da2-**************************"
_headers = {
"Content-Type": "application/graphql",
"x-api-key": API_KEY,
}
_transport = RequestsHTTPTransport(
headers = _headers,
url = ENDPOINT,
use_json = True,
)
_client = Client(
transport = _transport,
fetch_schema_from_transport = True,
)
def lambda_handler(event, context):
bucket = event['Records'][0]['s3']['bucket']['name']
key = unquote_plus(event['Records'][0]['s3']['object']['key'], encoding='utf-8')
logger.info("Function Start (deploy from S3) : Bucket={0}, Key={1}" .format(bucket, key))
fileName = os.path.basename(key)
dirPath = os.path.dirname(key)
dirName = os.path.basename(dirPath)
orgFilePath = u'/tmp/' + fileName
processedFilePath = u'/tmp/processed-' + fileName
if (key.startswith("public/processed/")):
logger.info("not start with public")
return
apiCreateTable(dirName, key)
keyOut = key.replace("public", "public/processed", 1)
logger.info("Output local path = {0}".format(processedFilePath))
try:
s3.download_file(Bucket=bucket, Key=key, Filename=orgFilePath)
orgImage = cv2.imread(orgFilePath)
grayImage = cv2.cvtColor(orgImage, cv2.COLOR_RGB2GRAY)
cv2.imwrite(processedFilePath, grayImage)
s3.upload_file(Filename=processedFilePath, Bucket=bucket, Key=keyOut)
apiCreateTable(dirName, keyOut)
logger.info("Function Completed : processed key = {0}".format(keyOut))
except Exception as e:
print(e)
raise e
finally:
if os.path.exists(orgFilePath):
os.remove(orgFilePath)
if os.path.exists(processedFilePath):
os.remove(processedFilePath)
def apiCreateTable(group, path):
logger.info("group={0}, path={1}".format(group, path))
try:
query = gql("""
mutation create {{
createSampleAppsyncTable(input:{{
group: \"{0}\"
path: \"{1}\"
}}){{
group path
}}
}}
""".format(group, path))
_client.execute(query)
except Exception as e:
print(e)
Pour ʻENDPOINT et ʻAPI_KEY
, reportez-vous aux paramètres d'API créés précédemment dans AppSync.
Veuillez le compresser, le télécharger sur S3 et le déployer sur Lambda.
Lorsque vous exécutez l'application Web et téléchargez une image, Lambda accède à AppSync, la détecte et la répertorie du côté de l'application Web. Même si je frappe directement l'URL avec le paramètre de requête, j'obtiens la liste d'AppSync et je la liste.
Le projet d'application Web (Vue) est le suivant. https://github.com/ww2or3ww/sample_vue_project/tree/work5
Le projet Lambda est ci-dessous. https://github.com/ww2or3ww/sample_lambda_py_project/tree/work3
C'était le premier sujet que j'ai posé à haute voix après avoir participé à JAWS UG Hamamatsu. N'est-il pas possible de spécifier la clé de partition DynamoDB ou la clé de tri dans l'API d'Amplify? Vous n'utilisez pas souvent DynamoDB sans paramètres clés, non? Je ne connais pas WebSocket en détail, mais est-ce quelque chose comme un long sondage? Je me souviens avoir parlé avec excitation.
Au fait, le réseautage est difficile, n'est-ce pas? Je respecte ceux qui peuvent se dire ingénieurs réseau. Pour être honnête, je ne sais pas si cela s'appelle MQTT sur WebSocket. Veuillez me le dire d'une manière facile à comprendre.
Les échantillons AppSync sont souvent considérés comme un ensemble avec Amplify CLI, ils ne sont donc utilisés que depuis le frontal. Application de chat, application TODO. DynamoDB est également une analyse complète. Je pense que DynamoDB a tendance à augmenter le nombre d'enregistrements, ou il a tendance à être utilisé à cette fin, et dans ce sens, l'analyse de tous les enregistrements n'est pas bonne.
Recommended Posts