В этой статье мы будем использовать AWS Amplify для создания облачного нативного приложения. Мы рассмотрим категории аутентификации, GraphQL API и хостинга AWS Amplify. Для фронтенда мы будем использовать Angular. Однако шаги, предпринятые здесь, должны быть аналогичными для других фреймворков.
Мы узнали, что такое Amplify, как Amplify работает за кулисами, и примеры использования Amplify в этой серии. Пришло время увидеть это в действии и получить практический опыт использования Amplify. В конце этой статьи у вас будет облачное нативное приложение.
- Предварительные условия
- Настройка Amplify CLI
- Установка зависимостей и запуск приложения
- Инициализация бэкенда
- Настройка фронтенда
- Добавление аутентификации Amplify
- Генерация ресурсов бэкенда для аутентификации
- Добавление компонента аутентификации во фронтенд
- Добавление функции выхода из системы
- Данные пользователя
- Подключение бэкенда с помощью GraphQL
- Генерация ресурсов бэкенда для API
- Подключение фронтенда к API
- Заполнение источника данных
- Получение данных из бэкенда
- Подписка на данные
- Ограничение Amplify GraphQL
- Лайки и комментарии
- GraphQL-запрос с фильтрами и пагинацией
- Пользовательские GraphQL-запросы, мутации и подписки
- Пользовательские GraphQL-резольверы
- Размещение нашего приложения на хостинге
- Настройка перенаправлений для нашего SPA
- (Дополнительно) Привязка доменного имени к вашему развертыванию
- Далее…
Предварительные условия
Прежде чем приступить к работе, нам нужно убедиться, что у нас все готово. Чтобы следовать этим инструкциям и создать свое приложение, вам необходимо иметь следующее:
- Активная учетная запись AWS.
- NodeJS: я использовал версию 14.17.5.
- Angular CLI: я использовал версию 13.1.4.
- Git: Необходим для проверки проекта примера.
- Amplify CLI: я использовал версию 7.6.22.
Настройка Amplify CLI
Прежде чем мы сможем начать использовать CLI, нам нужно настроить AWS Amplify CLI на использование нашей учетной записи AWS. Как только вы настроите CLI, мы можем приступить к работе.
Установка зависимостей и запуск приложения
Мы создали пример приложения AWS Amplify Angular, который вы можете клонировать. Проверьте ветку start_here и начните оттуда. Чтобы убедиться, что все работает, запустите npm run start
. Вы должны увидеть простое приложение под названием «The Amplify App»:
В настоящее время это приложение является простым приложением Angular без связанного бэкенда. С этого момента мы начнем использовать CLI для инициализации нашего проекта, генерации ресурсов бэкенда и подключения их к фронтенду.
Инициализация бэкенда
Первая команда, которую мы выполним, будет amplify init
. Вы должны увидеть результат, похожий на этот:
Evertsons-MBP:theamplifyapp evertsoncroes$ amplify init
Note: It is recommended to run this command from the root of your app directory
? Enter a name for the project theamplifyapp
The following configuration will be applied:
Project information
| Name: theamplifyapp
| Environment: dev
| Default editor: Visual Studio Code
| App type: javascript
| Javascript framework: angular
| Source Directory Path: src
| Distribution Directory Path: dist/theamplifyapp
| Build Command: npm run-script build
| Start Command: ng serve
? Initialize the project with the above configuration? Yes
Using default provider awscloudformation
? Select the authentication method you want to use: AWS profile
For more information on AWS Profiles, see:
https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html
? Please choose the profile you want to use default
⠴ Initializing project in the cloud...
После этого наш проект Amplify будет создан, и мы сможем увидеть несколько новых файлов в нашем репозитории. Если вам нужно повторить, что это за файлы и как работает Amplify, ознакомьтесь со второй частью этой серии блогов: Как работает AWS amplify?
Если вы создаете публичный проект, рекомендуется добавить amplify/team-provider-info.json
в .gitignore
, так как он содержит идентификаторы ресурсов, которые мы используем для Amplify. Это не создает угрозы безопасности, поскольку ваш проект защищен вашими учетными данными. Если несколько разработчиков работают над одним проектом, им всем нужен этот файл.
Если все работает, вы должны увидеть около 7 измененных файлов.
Настройка фронтенда
Теперь нам нужно установить соответствующие библиотеки фронтенда Amplify. В этом случае мы запускаем:
npm install --save aws-amplify @aws-amplify/ui-angular
Это установит библиотеку amplify и специфические для Angular элементы пользовательского интерфейса, которые мы будем использовать позже. После этого мы хотим настроить библиотеку Amplify с помощью нашего aws-exports.js
, добавив следующее в наш src/main.ts
:
import Amplify from 'aws-amplify';
import aws_exports from './aws-exports';
Amplify.configure(aws_exports);
Ваша IDE может пожаловаться на отсутствие определения типа в ./aws-exports
. Простым решением на данный момент является добавление allowJs:true
в наш tsconfig.json
.
Наконец, нам также нужно добавить следующее в src/polyfill.ts
:
(window as any).global = window;
(window as any).process = {
env: { DEBUG: undefined }
};
Нам нужно добавить их, поскольку они используются Amplify, но не присутствуют по умолчанию, начиная с Angular 6.
Вы должны увидеть около 5 изменений файлов после этого шага.
Добавление аутентификации Amplify
Теперь мы собираемся добавить функциональность аутентификации пользователей в наше приложение.
Генерация ресурсов бэкенда для аутентификации
Первое, что мы сделаем, это сгенерируем ресурсы бэкенда, которые помогут нам с аутентификацией, выполнив команду amplify add auth
. Вы должны увидеть результат, подобный этому:
Evertsons-MBP:theamplifyapp evertsoncroes$ amplify add auth
Using service: Cognito, provided by: awscloudformation
The current configured provider is Amazon Cognito.
Do you want to use the default authentication and security configuration? Default configuration
Warning: you will not be able to edit these selections.
How do you want users to be able to sign in? Username
Do you want to configure advanced settings? No, I am done.
✅ Successfully added auth resource theamplifyappfdeaa7e5 locally
✅ Some next steps:
"amplify push" will build all your local backend resources and provision it in the cloud
"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud
Теперь мы должны увидеть некоторые новые файлы, добавленные в наш проект, такие как файлы в разделе amplify/backend/auth
, которые представляют наши варианты аутентификации. Однако в бэкенде еще ничего не произошло. Нам нужно запустить amplify push
, чтобы перенести наши изменения на AWS и заставить CloudFormation создать ресурсы для нас:
Evertsons-MBP:theamplifyapp evertsoncroes$ amplify push
✔ Successfully pulled backend environment dev from the cloud.
Current Environment: dev
┌──────────┬───────────────────────┬───────────┬───────────────────┐
│ Category │ Resource name │ Operation │ Provider plugin │
├──────────┼───────────────────────┼───────────┼───────────────────┤
│ Auth │ theamplifyappfdeaa7e5 │ Create │ awscloudformation │
└──────────┴───────────────────────┴───────────┴───────────────────┘
? Are you sure you want to continue? Yes
⠋ Updating resources in the cloud. This may take a few minutes...
Добавление компонента аутентификации во фронтенд
Мы будем использовать компонент Amplify Authenticator UI для реализации аутентификации во фронтенде. Мы уже установили его ранее, однако теперь нам все еще нужно добавить его в src/app/app.module.ts
:
//Other imports
import { AmplifyAuthenticatorModule } from '@aws-amplify/ui-angular'; // <-- Add this
@NgModule({
declarations: [
//Existing declarations
],
imports: [
//other imports
AmplifyAuthenticatorModule // <-- Add this
],
// Other stuff
})
export class AppModule {}
Мы начнем с того, что просто защитим все наше приложение с помощью аутентификатора Amplify. Для этого добавьте следующее в src/app/app.component.html
:
<amplify-authenticator><!-- <--Add this -->
<app-header></app-header>
<div class="content-container">
<router-outlet></router-outlet>
</div>
<app-footer></app-footer>
</amplify-authenticator> <!-- <--Add this -->
Также нам нужно импортировать стилистику по умолчанию в наш src/app/styles.css
:
@import "@aws-amplify/ui-angular/theme.css";
/* other styles */
Если вы запустите свое приложение сейчас, вы должны увидеть аутентификатор Amplify:
Вы можете использовать его для создания учетной записи и входа в систему для просмотра приложения. Это полнофункциональный аутентификатор с функциями регистрации, входа, забытого пароля и активации по электронной почте. Он также предоставляет обратную связь при возникновении ошибок.
Существует несколько вариантов настройки этого пользовательского интерфейса. Вы можете узнать больше об аутентификаторе Amplify Authenticator в документации.
После создания учетной записи вы должны иметь возможность войти в консоль AWS, перейти к службе Cognito и увидеть пул пользователей с именем вашего проекта. Внутри этого пула пользователей вы должны увидеть свою новую учетную запись:
Добавление функции выхода из системы
Мы также хотим иметь возможность выйти из нашего приложения. Сначала мы добавим соответствующую кнопку в header.component.html:
<nav>
<!-- other existing code -->
<button class="aws-button" (click)="signOut()">Sign out</button> <!-- <-- Add this -->
</nav>
Затем мы добавляем логику выхода из приложения, которую мы получаем непосредственно от Amplify, в наш header.component.ts
:
import { Auth } from 'aws-amplify'; // <-- Add this
export class HeaderComponent implements OnInit {
// Other existing code
signOut() { // <-- Add this
Auth.signOut();
}
}
И теперь у нас есть кнопка выхода, которую мы можем использовать для выхода и возврата к аутентификатору Amplify.
Данные пользователя
Мы добавим текст Welcome <<username>>
в заголовок. Для получения этих данных мы можем использовать библиотеку Amplify Auth. Мы начнем с создания сервиса Angular, который назовем UserService
, который будет обрабатывать все потребности нашего вошедшего пользователя.
В терминале в корне вашего проекта выполните следующее:
ng generate service services/shared/user
Мы обновим новую службу следующим образом:
import { Injectable } from '@angular/core';
import { Auth } from 'aws-amplify';
export interface UserInfo {
email: string;
username: string;
}
@Injectable({
providedIn: 'root'
})
export class UserService {
constructor() {}
async getCurrentUserInfo(): Promise {
const userInfoResponse = await Auth.currentUserInfo();
return {
email: userInfoResponse.attributes.email,
username: userInfoResponse.username
};
}
}
Он использует библиотеку Amplify Auth для получения информации о текущем пользователе. Затем мы внесем некоторые изменения в наш файл header.component.ts
, чтобы вызвать эту функцию:
import { UserService, UserInfo } from '../../services/shared/user.service'; //<--- Add this
export class HeaderComponent implements OnInit {
//other code
currentUserName: string = ''; //<--- Add this
constructor(public router: Router, private userService: UserService ) { //<--- Add userService
//other code
}
ngOnInit(): void { //<--- Add this this.userService .getCurrentUserInfo() .then((userInfo: UserInfo) => {
this.currentUserName = userInfo.username;
})
.catch(error => {
console.log('Error while obtaining user: ', error);
});
}
}
И теперь, когда у нас есть переменная в компоненте заголовка с текущим именем пользователя, мы можем отобразить ее в файле header.component.html
:
<nav>
<!-- other code -->
<span class="welcome-text">Welcome {{ currentUserName }}</span> <!-- <--- add this -->
<button class="aws-button" (click)="signOut()">Sign out</button>
</nav>
И, наконец, мы добавим некоторые стили в header.component.css
, чтобы мы могли видеть текст на темном фоне:
.welcome-text {
color: white;
margin-right: 16px;
}
И теперь у нас есть текст, который показывает нам имя пользователя, который вошел в систему:
Подробности смотрите в документации Amplify Auth.
Теперь мы изменили несколько вещей:
- Мы добавили пользовательский интерфейс Amplify Authenticator.
- Мы добавили кнопку выхода из системы.
- Мы добавили данные о пользователе в заголовок.
Подключение бэкенда с помощью GraphQL
В этом разделе мы добавим API GraphQL для нашего приложения, который заменит текущие имитационные данные in-memory, используемые для страницы API в нашем приложении. Если вы перейдете на вкладку API, вы увидите, что у нас есть список постов, которые могут иметь список лайков и комментариев. Мы будем моделировать это на GraphQL.
Генерация ресурсов бэкенда для API
Для начала нам нужно добавить конечную точку ресурса:
Evertsons-MBP:theamplifyapp evertsoncroes$ amplify add api
? Select from one of the below-mentioned services: GraphQL
? Here is the GraphQL API that we will create. Select a setting to edit or continue Authorization modes: API key (default, expiration time: 7 days from now)
? Choose the default authorization type for the API Amazon Cognito User Pool
Use a Cognito user pool configured as a part of this project.
? Configure additional auth types? No
? Here is the GraphQL API that we will create. Select a setting to edit or continue Continue
? Choose a schema template: One-to-many relationship (e.g., “Blogs” with “Posts” and “Comments”)
⚠️ WARNING: Some types do not have authorization rules configured. That means all create, read, update, and delete operations are denied on these types:
- Blog
- Post
- Comment
Learn more about "@auth" authorization rules here: https://docs.amplify.aws/cli/graphql/authorization-rules
GraphQL schema compiled successfully.
Edit your schema at /Users/evertsoncroes/Documents/development/private/theamplifyapp/amplify/backend/api/theamplifyapp/schema.graphql or place .graphql files in a directory at /Users
/evertsoncroes/Documents/development/private/theamplifyapp/amplify/backend/api/theamplifyapp/schema
✔ Do you want to edit the schema now? (Y/n) · yes
✅ Successfully added resource theamplifyapp locally
✅ Some next steps:
"amplify push" will build all your local backend resources and provision it in the cloud
"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud
Важно изменить метод аутентификации с API-ключа на Amazon Cognito User Pool, чтобы использовать ресурсы Auth, которые мы создали в предыдущем разделе.
Теперь у нас есть несколько новых файлов, созданных для нас Amplify CLI. Мы начнем с редактирования amplify/backend/api/schema.graphql
, чтобы он выглядел следующим образом:
type Post
@model
@auth(rules: [{ allow: owner }, { allow: private, operations: [read] }]) {
id: ID!
title: String!
description: String
likes: [Like] @hasMany
comments: [Comment] @hasMany
}
type Like
@model
@auth(rules: [{ allow: owner }, { allow: private, operations: [read] }]) {
id: ID!
post: Post @belongsTo
}
type Comment
@model
@auth(rules: [{ allow: owner }, { allow: private, operations: [read] }]) {
id: ID!
post: Post @belongsTo
content: String!
}
В этом примере мы определили 3 типа GraphQL Object для Post, Likes и Comments. Мы не указываем поле даты, потому что по умолчанию для каждого типа мы получаем поле createdAt и updatedAt.
Специфические для Amplify части этой схемы — это директивы, которые можно заметить по префиксу @. Здесь используются следующие директивы:
- @model: Это создает таблицу DynamoDB для поддержки этой модели. В данном случае будет создано 3 таблицы.
- @auth: Это правила авторизации для данного типа. Здесь описаны следующие правила:
- Владелец (создатель) записи имеет право выполнять все операции над этой записью.
- К каждому элементу в БД будет добавлено поле «owner», которое содержит имя пользователя, вошедшего в систему и создавшего элемент.
- Только вошедшие в систему пользователи (private) могут читать записи данного типа
- @hasMany: Создает связь «один-ко-многим» с другим типом. В нашем примере выше, сообщения имеют много комментариев и лайков.
- @belongsTo: Создает отношение «многие-к-одному» с другим типом. В нашем примере комментарии относятся к одному посту, а лайки — к одному сообщению.
Вы можете узнать больше о директивах или правилах авторизации в документации Amplify.
После настройки нашей схемы мы запускаем amplify push
и выбираем yes. Затем нам зададут несколько вопросов, связанных с graphql:
? Do you want to generate code for your newly created GraphQL API Yes
? Choose the code generation language target angular
? Enter the file name pattern of graphql queries, mutations and subscriptions src/graphql/**/*.graphql
? Do you want to generate/update all possible GraphQL operations - queries, mutations, and subscriptions Yes
? Enter maximum statement depth [increase from default if your schema is deeply nested] 2
? Enter the file name for the generated code src/app/API.service.ts
В результате будет сгенерировано много внешнего кода, специфичного для нашей схемы, чтобы мы могли легко использовать наш бэкенд GraphQL.
Подключение фронтенда к API
Было сгенерировано несколько файлов, о которых важно рассказать. Прежде всего, это файл API.service.ts. Этот файл содержит все сгенерированные типы и утверждения, которые могут быть использованы с GraphQL API и внедрены в качестве Angular Service в компоненты и сервисы Angular.
Во-вторых, в корне нашего проекта теперь есть каталог под названием graphql. Этот файл содержит сгенерированные GraphQL-запросы, мутации и подписки, а также JSON-представление нашей схемы GraphQL. Эти файлы используются в качестве входных данных для генерации API.service.ts
. Мы рассмотрим эти файлы позже в статье.
Заполнение источника данных
Мы начнем с обновления нашего post.service.ts
, чтобы сохранять новые посты в бэкенде Amplify, а не в mockObject
. Мы внесем следующие изменения:
//Other imports
import { APIService } from 'src/app/API.service'; // <--- Add this
@Injectable({
providedIn: 'root'
})
export class PostService {
//other code
constructor(private api: APIService) { // <--- Add api to constructor
}
addPost(title: string, description: string) { // <--- replace current addPost with new code
this.api.CreatePost({
title,
description
});
}
//other code
}
Здесь мы импортируем сгенерированный API-сервис и используем одну из сгенерированных функций, CreatePost
, для создания нового элемента поста в нашем бэкенде. Если вы найдете определение функции CreatePost
в src/app/API.service
, вы увидите, какие параметры она ожидает. В данном случае достаточно добавить заголовок и описание.
Теперь, когда мы добавляем посты, они будут сохраняться.
Получение данных из бэкенда
Следующим шагом будет получение всех наших постов из бэкенда. Мы внесем следующие изменения в наш post.service.ts
:
// other imports
import { APIService, Post as AmplifyPost } from 'src/app/API.service'; // <--- Add this new import
@Injectable({
providedIn: 'root'
})
export class PostService {
private posts: BehaviorSubject<Post[]> = new BehaviorSubject<Post[]>([]); // <--- remove mockposts and its usage completely
private postsData: Post[] = [];
constructor(private api: APIService, private userService: UserService) {
this.setOnPostCreateSubscription();
}
// Other code
//Update this function
getAllPosts(): Observable<Post[]> {
this.api.ListPosts().then(response => {
const responsePosts: Post[] = [];
response.items.forEach(item => {
const post = this.convertToPost(item as AmplifyPost);
responsePosts.push(post);
});
this.posts.next(responsePosts);
});
return this.posts.asObservable();
}
//Add this function
private convertToPost(amplifyPost: AmplifyPost): Post {
const {
id,
title,
description,
owner,
createdAt,
likes,
comments
} = amplifyPost;
const likesItems = likes ? likes.items : undefined;
const commentsItems = comments ? comments.items : undefined;
return {
id,
title,
description: description ? description : '',
author: owner ? owner : '',
date: new Date(createdAt),
likes: likesItems ? likesItems.length : 0,
comments: commentsItems ? commentsItems.length : 0
};
}
}
Здесь мы делаем несколько вещей:
- Импортируем сгенерированный интерфейс
Post
и присваиваем ему псевдоним, посколькуPost
уже существует и используется для UI-модели нашего компонента Post. - Полностью удаляем имитацию данных, так как теперь этот сервис будет обслуживать данные из бэкенда Amplify
- Использование сгенерированной функции
listPosts
для получения всех постов в нашем бэкенде. - Преобразование постов, полученных из бэкенда Amplify, в модель Post, которую мы хотим использовать в нашем пользовательском интерфейсе. Существенное различие здесь заключается в том, что мы хотим подсчитать количество лайков и комментариев и вернуть числа.
Если мы запустим наше приложение сейчас, мы должны увидеть новые данные, полученные из бэкенда. Если мы добавим новый пост и обновим страницу, мы увидим последний пост в списке.
Подписка на данные
Было бы неплохо, чтобы новое сообщение появлялось в списке сразу после его добавления. Один из способов добиться этого — вызвать getAllPosts
после того, как addPosts
был успешным. Однако есть способ получше: Amplify GraphQL также позволяет нам подписываться на определенные события.
В данном случае мы можем подписаться на событие создания поста, внеся следующие изменения в наш post.service.ts
:
import { UserService, UserInfo } from '../shared/user.service'; // Add this import
@Injectable({
providedIn: 'root'
})
export class PostService {
private postsData: Post[] = []; // <-- add this
constructor(private api: APIService, private userService: UserService) {
this.setOnPostCreateSubscription(); // <-- add this
}
//Add this function
private async setOnPostCreateSubscription() {
const userInfo: UserInfo = await this.userService.getCurrentUserInfo();
if (userInfo) {
this.api.OnCreatePostListener(userInfo.username).subscribe(response => {
const responseData = response.value.data;
if (responseData && responseData.onCreatePost) {
const post = this.convertToPost(
responseData.onCreatePost as AmplifyPost
);
this.postsData.push(post);
this.posts.next(this.postsData);
}
});
}
}
getAllPosts(): Observable<Post[]> {
this.api.CustomListPosts().then(response => {
const responsePosts: Post[] = [];
response.items.forEach(item => {
const post = this.convertToPost(item as AmplifyPost);
responsePosts.push(post);
});
this.postsData = responsePosts; // <-- add this
this.posts.next(responsePosts);
});
return this.posts.asObservable();
}
}
Мы внесли эти изменения:
- Импортируйте
UserService
, который мы создали в предыдущем разделе. Это необходимо из-за ограничения в подписке Amplify GraphQL (см. ниже). - Создайте массив, который хранит состояние последних полученных данных. Нам это нужно, поскольку подписка возвращает только новый добавленный пост. Нам нужно добавить только что созданный пост в этот список и вернуть его компоненту.
- Мы вызываем
onCreatePostListener
с именем пользователя, вошедшего в систему, и преобразуем ответ этой подписки в объект нашей моделиPost
, аналогично тому, как мы делали это для запроса.
Ограничение Amplify GraphQL
В настоящее время невозможно использовать правило авторизации владельца в вашей схеме GraphQL и оформить подписку на объект без указания имени пользователя владельца. Если вы хотите иметь возможность подписки на все объекты типа, независимо от того, кто его создал, вам нужно удалить правило авторизации владельца в вашей схеме. Однако это означает, что у вас больше не будет поля owner во всех ваших объектах в базе данных и что любой вошедший в систему пользователь сможет обновлять и удалять сообщения, которые ему не принадлежат.
Для того чтобы пример подписки был рабочим, мы создали подписку для текущего пользователя, то есть вы будете получать обновления только для тех сообщений, которые вы сами размещаете. Надеемся, что в будущем мы сможем иметь больше гибкости в отношении подписок. Тем не менее, этот пример должен показать, как легко настроить подписки, и есть еще несколько случаев, когда это может быть полезно.
Лайки и комментарии
Для сервисов Like
и Comment
мы выполнили шаги, аналогичные тем, что были выполнены для Post
. Вы можете просмотреть все эти шаги в Git-коммитах, которые мы приведем в конце этого раздела. Однако есть несколько ключевых моментов, которые мы все же хотим осветить и с которыми мы столкнулись при переносе лайков и комментариев на бэкенд Amplify.
GraphQL-запрос с фильтрами и пагинацией
Когда мы хотим запросить лайки или комментарии, мы хотим запросить их только в том случае, если они относятся к посту, который мы сейчас просматриваем во фронтенде. К счастью, генерируемые функции, которые мы используем для запросов в бэкенде, имеют встроенные функции фильтрации и пагинации.
Если мы посмотрим на определение функции ListLikes
в API.service.ts
, то увидим следующую подпись:
async ListLikes(
filter?: ModelLikeFilterInput,
limit?: number,
nextToken?: string
): Promise<ListLikesQuery> {
//code
}
В ModelLikeFilterInput
содержатся опции для фильтрации результатов на основе нескольких условий. Щелкните по ним, чтобы увидеть все возможности. Мы также можем видеть параметры limit и nextToken, которые используются для пагинации. Поскольку мы еще не встроили пагинацию в это приложение, мы обратимся к документации по пагинации.
Для запроса только тех лайков, которые принадлежат определенному посту, мы используем следующий код:
getLikesForPostId(postId: string) {
this.api.ListLikes({ postLikesId: { eq: postId } }).then(response => {
//other code
Пользовательские GraphQL-запросы, мутации и подписки
Если вы следуете шаблонам, которые мы показывали до сих пор, и у вас есть посты, лайки и комментарии, использующие бэкенд Amplify, вы заметите, что все посты по-прежнему показывают 0 лайков и комментариев в обзоре поста. Это ошибка, и она связана со значениями, которые извлекаются в сгенерированном запросе GraphQL, используемом в функции listPosts.
Если мы проверим определение запроса в src/graphql/queries.graphl
, то увидим следующее:
query ListPosts(
$filter: ModelPostFilterInput
$limit: Int
$nextToken: String
) {
listPosts(filter: $filter, limit: $limit, nextToken: $nextToken) {
items {
id
title
description
likes {
nextToken
}
comments {
nextToken
}
createdAt
updatedAt
owner
}
nextToken
}
}
Мы видим, что для лайков и комментариев извлекается только поле nextToken
. Поле items
не извлекается вообще, поэтому наш фронтенд по умолчанию имеет значение 0. К счастью, мы можем определить собственные запросы.
Мы можем создать новый файл src/app/custom-queries.graphql
со следующим содержимым:
query CustomListPosts(
$filter: ModelPostFilterInput
$limit: Int
$nextToken: String
) {
listPosts(filter: $filter, limit: $limit, nextToken: $nextToken) {
items {
id
title
description
likes {
items {
id
}
}
comments {
items {
id
}
}
createdAt
updatedAt
owner
}
nextToken
}
}
Теперь мы запросим элементы на наличие лайков и комментариев и получим только идентификаторы, поскольку мы хотим только подсчитать их. После добавления этого файла мы можем запустить в терминале следующую команду:
amplify codegen
Это сгенерирует новый код, который вы можете использовать во фронтенде без необходимости запускать amplify push. Теперь мы можем обновить наш post.service.ts
, чтобы использовать этот новый запрос:
getAllPosts(): Observable<Post[]> {
this.api.CustomListPosts().then(response => { // <-- updated here
//code
Если мы запустим приложение, то увидим правильные счетчики лайков и комментариев.
Пользовательские GraphQL-резольверы
В нашем текущем примере мы получаем лайки и комментарии и подсчитываем их во фронтенде, чтобы показать счетчики. Мы также можем обновить схему GraphQL для Post
и включить поля likesCount
и commentsCount
и определить пользовательскую логику для этих полей.
Это позволит бэкенду вычислять эти числа для нас и возвращать их на фронтенд. Демонстрация этого была бы слишком длинной для этой статьи, поэтому мы обратимся к документации по конфигурации резолвера AWS Lambda, где объясняется, как это настроить.
Мы внесли довольно много изменений:
- Мы добавили конечную точку API.
- Мы обновили схему GraphQL.
- Мы перенесли изменения в бэкенд.
- Мы добавили посты в бэкенд GraphQL.
- Мы извлекли сообщения из бэкенда GraphQL.
- Мы добавили подписки на сообщения.
- Мы добавили Likes в бэкенд GraphQL.
- Мы извлекли Likes из бэкенда GraphQL.
- Мы исправили подписки на сообщения.
- Мы создали пользовательский запрос для получения списка постов.
- Мы добавили подписку на лайки.
- Мы добавили Комментарии в бэкенд GraphQL.
- Мы получаем комментарии из бэкенда GraphQL.
- Мы добавили подписки на Комментарии.
Размещение нашего приложения на хостинге
Теперь, когда наше приложение работает локально, пришло время разместить его на AWS, чтобы оно было доступно онлайн. Мы собираемся сделать это, добавив категорию хостинга Amplify. Перед этим нам нужно выполнить следующие шаги:
- Войдите в консоль AWS с помощью браузера по умолчанию.
- Внесите весь свой код в Git.
- Обновите бюджет
initial
вangular.json
до2mb
.
Мы выполним следующую команду для добавления хостинга:
Evertsons-MBP:theamplifyapp evertsoncroes$ amplify add hosting
? Select the plugin module to execute Hosting with Amplify Console (Managed hosting with custom domains, Continuous deployment)
? Choose a type Continuous deployment (Git-based deployments)
? Continuous deployment is configured in the Amplify Console. Please hit enter once you connect your repository
Откроется консоль AWS, которая позволит нам подключить наш репозиторий к конвейеру CI/CD:
Перейдите на вкладку Hosting environments и выберите свой Git-репозиторий:
Нажмите на connect branch. После авторизации в репозитории Git выберите репозиторий и ветку, где существует последняя версия вашего кода, и нажмите на Next.
На следующей странице важно выбрать среду, которую вы будете использовать для этого развертывания. В данном случае мы создали только среду dev, поэтому мы будем использовать ее:
Если у вас нет существующей служебной роли для проектов Amplify, нажмите на Create new role, чтобы создать ее, и нажмите на кнопку refresh, чтобы она появилась в качестве опции.
Если вы прокрутите страницу до самого низа, то увидите настройки сборки по умолчанию. На данный момент они работают, однако если в будущем вы захотите расширить сборку, включив в нее больше фаз или шагов, вы всегда сможете их изменить.
Когда мы нажмем кнопку next, мы получим сводку выбранных нами параметров. Просмотрите их и нажмите на Save and deploy.
С этого момента каждый раз, когда вы нажимаете на ветку разработки, будет запускаться сборка, и живое приложение будет обновляться. Вот как это выглядит во время сборки:
Вы можете щелкнуть на любой из фаз, например, на этапе обеспечения, чтобы увидеть подробный журнал происходящего:
Когда сборка и развертывание завершены, мы видим, что все этапы пройдены и есть ссылка для тестирования нашего приложения:
Настройка перенаправлений для нашего SPA
Если вы нажмете на ссылку, вы увидите свое приложение, где вы можете войти в систему и увидеть главную страницу. Однако, если вы нажмете на API, то получите ошибку Access Denied. Для одностраничных приложений нам нужно добавить дополнительную настройку в консоли Amplify в нашем проекте, связанную с перезаписью и перенаправлениями:
Настройки таковы:
- Адрес источника:
</^[^.]+$|.(?!(css|gif|ico|jpg|js|png|txt|svg|woff|woff2|ttf|map|json)$)
([^.]+$)/>. - Целевой адрес:
/index.html
. - Тип: 200 (Перезапись).
- Страна: (оставьте пустым).
Подробности см. в документации Amplify по перенаправлениям одностраничных приложений.
(Дополнительно) Привязка доменного имени к вашему развертыванию
Один дополнительный шаг, который вы можете предпринять, это связать доменное имя с одним из ваших развертываний. В этом случае мы создадим новое окружение для нашего проекта, свяжем его с основной веткой, а затем привяжем доменное имя «theamplifyapp.com» к этому развертыванию.
Для начала я выполню следующую команду в терминале:
Evertsons-MBP:theamplifyapp evertsoncroes$ amplify init
Note: It is recommended to run this command from the root of your app directory
? Do you want to use an existing environment? No
? Enter a name for the environment prod
? Choose your default editor: Visual Studio Code
Using default provider awscloudformation
? Select the authentication method you want to use: AWS profile
For more information on AWS Profiles, see:
https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html
? Please choose the profile you want to use default
Adding backend environment prod to AWS Amplify app: d1ekyrd95b627y
⠴ Initializing project in the cloud...
После этого мы можем запустить amplify push
и выполнить шаги, которые мы сделали для среды dev.
После этого мы можем зайти в консоль Amplify, нажать на General, прокрутить до самого низа и нажать на connect branch. Там мы выберем мастер-ветку и среду prod:
Затем мы нажимаем на next, сохраняем и развертываем и ждем успешной сборки.
После этого мы можем перейти в Route53 в консоли AWS и зарегистрировать доменное имя. Обратите внимание, что это будет стоить денег! В данном случае я зарегистрировал домен theamplifyapp.com.
Вернувшись в консоль Amplify, перейдите на вкладку Управление доменами и выберите Добавить домен. Мы должны найти наш зарегистрированный домен в списке доступных доменов и выбрать его. Затем мы нажимаем на Configure domain и устанавливаем его на сборку мастер-ветки:
После нажатия на кнопку Сохранить процесс должен начаться. Когда он завершится, мы сможем посетить наше приложение на нашем совершенно новом домене!
Мы сделали два основных изменения:
- Мы добавили хостинг Amplify.
- Мы обновили бюджет Angular до 2 Мб. Обновленный бюджет Angular до 2 Мб.
Далее…
С помощью всего нескольких команд Amplify и изменений кода мы..:
- Создали облачное нативное приложение…
- Защищенное аутентификацией…
- Подкрепленное бэкендом GraphQL…
- С полностью настроенным конвейером CI/CD…
- Размещено в облаке AWS…
- Подключен через зарегистрированное доменное имя
Для каждой из этих категорий есть еще множество вариантов настройки. Однако, надеюсь, стало понятно, насколько мощным может быть Amplify.
В следующей части этой серии мы продолжим работу над нашим приложением и добавим категорию Amplify Storage. Мы будем использовать ее для создания библиотеки изображений, куда мы сможем загружать изображения.