Dieser Artikel ist ein praktischer Artikel zum Überprüfen und Korrigieren der durch die Entwicklung von Serverless Web App Mosaic gewonnenen Erkenntnisse. Es ist eines von w2or3w / items / 87b57dfdbcf218de91e2).
Es wäre schön, diesen Artikel zu lesen, nachdem man sich Folgendes angesehen hat.
Eine API namens AppSync wird zur Datenverwaltung von hochgeladenen und verarbeiteten Bildern sowie zur Datenübertragung mit dem Client verwendet. DynamoDB wird als Datenquelle für AppSync verwendet. AppSync kann auch mit der Amplify-CLI eingerichtet werden, aber ich schien nicht in der Lage zu sein, den DynanoDB-Partitionsschlüssel oder den Sortierschlüssel anzugeben, sodass ich die Amplify-CLI nicht verwende. Erstellen Sie DynamoDB und AppSync in der AWS-Konsole. Anfrage von Vue am Frontend mit Amplify und von Lambda (Python) am Backend per HTTP.
Ich kann AppSync mit der Amplify-CLI einrichten, aber anscheinend kann ich den Partitionsschlüssel und den Sortierschlüssel von DynamoDB nicht angeben. Ich kann es vielleicht tun, aber ich wusste nicht, wie ich es tun soll. Wenn jemand weiß, lassen Sie es mich bitte wissen. Es ist also etwas problematischer als die Befehlszeile, aber machen wir es mit der AWS-Konsole.
Erstellen Sie zuerst DynamoDB als Datenquelle für AppSync. AWS Console> DynamoDB> Tabelle erstellen Erstellen Sie eine Tabelle mit den folgenden Einstellungen. Tabellenname: sample_appsync_table Partitionsschlüssel: Gruppe (Zeichenfolge) Sortierschlüssel: Pfad (Zeichenfolge)
Sobald DynamoDB erstellt wurde, ist es Zeit, AppSync zu erstellen. AWS Console> AppSync> API erstellen
Schritt 1: Erste Schritte Wählen Sie "DynamoDB-Tabelle importieren" und klicken Sie auf "Start". ![Screenshot 2020-01-02 at 23.36.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394775/0d34eb39-937e-1b41-215e- 5216cc8228dc.png) Schritt 2: Erstellen Sie ein Modell Wählen Sie die zuvor erstellte Tabelle aus (sample_appsync_table). Wählen Sie "Neue Rolle" unter "Vorhandene Rolle erstellen oder verwenden". Klicken Sie auf die Schaltfläche "Importieren". Klicken Sie einfach auf die Schaltfläche "Erstellen". Schritt 3: Ressource erstellen Legen Sie den API-Namen fest und klicken Sie auf die Schaltfläche "Erstellen".
AWS Console> AppSync> sample_appsync_table> Im Menü Schema
Laden Sie schema.json
herunter. Diese Datei wird in der Webanwendung verwendet.
AWS Console> AppSync> sample_appsync_table> Über das Einstellungsmenü Überprüfen Sie die Informationen von "API URL" und "API KEY" in API Detail. Diese Informationen werden in der App verwendet.
Belassen Sie den Authentifizierungsmodus als "API-Schlüssel". Das Ablaufdatum des API-Schlüssels beträgt standardmäßig 7 Tage. Sie können es jedoch durch Bearbeiten auf 365 Tage verlängern. Ich werde einen weiteren Artikel darüber schreiben, wie der Authentifizierungsmodus als Cognito-Benutzer wie Storage verwendet wird.
Aktualisieren Sie nach dem Einrichten von AppSync die Webanwendung weiter.
Erstellen Sie einen src / graphql-Ordner und fügen Sie drei Dateien hinzu.
src/graphql/schema.json
Fügen Sie die heruntergeladene Datei unverändert zum Projekt hinzu.
src/graphql/queries.js
export const listSampleAppsyncTables = `query listSampleAppsyncTables($group: String) {
listSampleAppsyncTables(
limit: 1000000
filter: {
group: {eq:$group}
}
)
{
items
{
group
path
}
}
}
`;
Es ist eine Abfrage, um die Datensatzliste durch Angabe der Gruppe des Partitionsschlüssels abzurufen. Dies ist ein Rätsel, aber wenn Sie das Limit nicht angeben, können Sie die Daten nicht abrufen. Ich denke, es ist eine AppSync-Spezifikation, nicht graphql, aber was ist damit? Ich habe eine relativ große Anzahl von 1000000 angegeben, aber ehrlich gesagt ist es zu subtil. Wenn jemand eine bessere Art zu schreiben kennt, lass es mich wissen.
src/graphql/subscriptions.js
export const onCreateSampleAppsyncTable = `subscription OnCreateSampleAppsyncTable($group: String) {
onCreateSampleAppsyncTable(group : $group) {
group
path
}
}
`;
Es ist ein Abonnement, um die Gruppe des Partitionsschlüssels anzugeben und mit den Informationen benachrichtigt zu werden, wenn der Datensatz eingefügt wird. Ich habe "Wenn ein Datensatz eingefügt wird" geschrieben, aber es ist nicht möglich, einen Datensatz direkt in DynamoDB einzufügen. Er muss durch Erstellen in AppSync eingefügt werden.
Fügen Sie die für den Zugriff auf AppSync erforderlichen Informationen zu src / aws-exports.js
hinzu.
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;
Die in dieser Datei enthaltenen Informationen sind wichtig. Gehen Sie daher vorsichtig damit um, damit sie nicht auslaufen.
Implementieren Sie nach Auswahl und Hochladen eines Bilds in Home eine Liste mit Informationen zum hochgeladenen Bild und zum monochrom verarbeiteten Bild am Seitenübergangsziel.
Fügen Sie eine Seite mit dem Namen Liste hinzu. Router-Einstellungen dafür.
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,
},
]
});
Listenseitenansicht
src/views/List.vue
<template>
<List />
</template>
<script>
import List from '../components/List'
export default {
components: {
List
}
}
</script>
Seitenkomponenten auflisten
src/components/List.vue
<template>
<v-container>
<p>aufführen</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>
Rufen Sie die Gruppe im Abfrageparameter ab. In gemountet, bevor der Bildschirm angezeigt wird, werden die Datensatzdaten durch Angabe der Gruppe erfasst, oder die Datensatzdaten werden erfasst, wenn das Einfügeereignis empfangen wird. Die erfassten Datensatzdaten werden in einem Elementvariablenarray namens dataList gespeichert und nebeneinander in der V-Liste auf dem Bildschirm angezeigt. In der V-Liste werden der Pfad und das Bild der Datensatzdaten angezeigt. Der Zugriff auf das Bild erfolgt durch Abrufen der Adresse mit dem Ablaufdatum (30 Minuten) bei Strage.
src/components/Home.vue
<template>
<v-container>
<p>Zuhause</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>
Verwenden Sie uploadSelectedFile, um nach dem Hochladen der Datei zur Listenseite zu wechseln. Zu diesem Zeitpunkt wird ein Abfrageparameter namens group angehängt.
Damit ist die Reparatur des Frontends (Webanwendung) abgeschlossen, die Funktionsprüfung wird jedoch nach Abschluss der Backend-Seite durchgeführt.
Implementiert das Einfügen eines Datensatzes einer Datei, die aus einer Webanwendung hochgeladen wurde, oder eines monochromen Bildpfads (S3-Schlüssel), der von Lambda über AppSync generiert und hochgeladen wurde.
Installieren Sie gql.
pip install gql -t .
Aktualisieren Sie lambda_function.py
wie folgt:
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)
Informationen zu "ENDPOINT" und "API_KEY" finden Sie in den API-Einstellungen, die zuvor in AppSync erstellt wurden. Bitte komprimieren Sie es, laden Sie es in S3 hoch und stellen Sie es in Lambda bereit.
Wenn Sie die Web-App ausführen und ein Bild hochladen, drückt Lambda auf AppSync, erkennt es und listet es auf der Seite der Web-App auf. Selbst wenn ich die URL mit dem Abfrageparameter direkt drücke, erhalte ich die Liste von AppSync und liste sie auf.
Das Webanwendungsprojekt (Vue) sieht wie folgt aus. https://github.com/ww2or3ww/sample_vue_project/tree/work5
Das Lambda-Projekt ist unten. https://github.com/ww2or3ww/sample_lambda_py_project/tree/work3
Dies war das erste Thema, das ich laut gefragt habe, nachdem ich an JAWS UG Hamamatsu teilgenommen hatte. Ist es nicht möglich, den DynamoDB-Partitionsschlüssel oder den Sortierschlüssel in der Amplify-API anzugeben? Sie verwenden DynamoDB nicht oft ohne Schlüsseleinstellungen, oder? Ich kenne WebSocket nicht im Detail, aber ist es so etwas wie langes Abrufen? Ich erinnere mich, wie ich aufgeregt gesprochen habe.
Networking ist übrigens schwierig, nicht wahr? Ich respektiere diejenigen, die sich Netzwerktechniker nennen können. Um ehrlich zu sein, verstehe ich das nicht wirklich, selbst wenn es MQTT über WebSocket heißt. Bitte sagen Sie es mir auf leicht verständliche Weise.
AppSync-Beispiele werden häufig als Set mit Amplify CLI bezeichnet, sodass sie nur vom Front-End aus verwendet werden. Chat App, TODO App. DynamoDB ist auch ein vollständiger Scan. Ich denke, dass DynamoDB dazu neigt, die Anzahl der Datensätze zu erhöhen, oder es wird tendenziell für diesen Zweck verwendet, und in diesem Sinne ist das Scannen aller Datensätze nicht gut.
Recommended Posts