AWS Amplify는
모바일 및 프론트 웹 개발자가 AWS에서 구동되는 풀스택 앱을 개발할 수 있게 도와주는 서비스 이다.
장점으로는
- 혁신적인 앱 개발: Amplify Library를 통해 Auth, AI/ML 등을 단 몇 줄의 코드로 개발할 수 있다.
- 몇 분만에 백엔드 구성: AWS S3나 Amazon Congito와 같은 AWS 서비스를 사용하여 회원가입, 스토리지, API 등의 백엔드를 자동으로 구성할 수 있다. 특히 Amplify CLI를 통해 간단한 명령으로 앱을 위한 백엔드를 개인화 할 수 있다.
- 편리한 배포 및 확장: AWS Amplify콘솔에서 비즈니스 성장에 따라 가용성을 수정할 수 있다. 몇 분 만에 확장 가능한 정적 웹 사이트 및 웹앱 배포가 가능하다.
자세한 내용은 서비스 페이지에서 확인
Amplify 를 이용해 iOS Todo앱의 백엔드를 구성해볼 것 이다.
대략적인 순서는 이렇다.
- AWS Amplify CLI 설치
- iOS Todo Xcode 프로젝트 생성
- 프로젝트 빌드에 Amplify 세팅
- Todo Project 에서 모델 파일 생성
- AWS Amplify 프레임워크 Todo Project 에 integration
- 해당 프로젝트 Cloud 에 연동
- Todo List UI 구성 및 앱 완성
1. AWS Amplify CLI 설치 (Mac 환경)
Node와 NPM 이 설치되어 있어야 한다.
- Node 버전 10.x 이상
- npm 버전 6.x 이상
버전확인은 터미널에서 node -v, npm -v 로 확인할 수 있다.
설치 안된 사람은 이 포스팅 참고
이제 amplify cli 설치해 보겠다.
터미널에서 코드 입력
npm install -g @aws-amplify/cli
1-2. CLI Configuration
터미널에서 아래 코드 입력
amplify configure
configuration이 시작되면 자동으로 AWS Console이 열린다.
여기서 AWS에 로그인하고 터미널로 돌아와 Enter 를 누른다.
그럼 Region 을 선택하라고 나오는데 나는 서울리전 이므로 ap-northeast-2 를 선택한다.
그 후 IAM username 을 입력하라고 한다. IAM 은 일종의 admin 권한이 아닌 제한된 권한을 가지는 유저이다.
원하는 이름으로 작성하면 작성된 이름으로 AWS IAM Dashboard 가 뜬다.
따로 건들이지 않고 Next로 하여 새로운 유저를 만든다.
Access Key 와 Secret Access Key 가 부여되는데 Secret Access Key 의 경우는 한번밖에 발급이 안되기 때문에 .csv 다운로드로 소중하게 간직한다.
그리고 Access Key 와 access key 를 복사해 터미널로 돌아와 붙여넣는다.
profile name 은 default로 설정한다.
Amplify CLI 준비 끝
2. Todo Xcode 프로젝트 생성
xcode 에서 일반적인 방법으로 프로젝트를 하나 생성한다. (SingleView App)
iOS 프로젝트에 Amplify 프레임워크를 적용하려면 Cocoapod 을 사용해야 한다.
[코코아팟 모르는 사람은 아랫글 참조]
일반적으로 pod 설정하듯이 해당 프로젝트 디렉토리로 가서
pod init
해준다.
Podfile 내용은
pod 'Amplify'
pod 'Amplify/Tools'
pod 'AmplifyPlugins/AWSAPIPlugin'
pod 'AmplifyPlugins/AWSDataStorePlugin'
이렇게 채우고
pod install --repo-update
를 해주면 막 좌좌작 깔린다.
3. 프로젝트 빌드에 Amplify 세팅
xcode 프로젝트를 열되 밑에 cocoapod 적용된 workspace 로 연다.
Todo Project 에서 Target -> Build Phase 로 들어간다.
여기서 새로운 Run Script Phase 를 + 버튼을 통해 만든다.
Run Script의 순서를 Compile Sources 전 단계로 옮긴다. (드래그 하면 이동됨)
Run Script 탭을 열러 shell script 에 아래의 코드를 작성한다.
"${PODS_ROOT}/AmplifyTools/amplify-tools.sh"
Build Phase 에 추가가 완료되었다. 이제 프로젝트를 빌드해보면 Amplify tool도 같이 빌드되는 걸 볼 수 있다.
만약 처음 Build 하는 경우면 프로젝트 디렉토리에 새로운 파일들이 생긴걸 볼 수 있다.
- amplifyConfig Folder: 여러가지 config 파일과 미리 만들어진 샘플 파일들이 있는 디렉토리이다.
- amplifytools.xcconfig: amplify tool의 동작을 설정하는 config 파일이다.
- amplifyconfiguration.json: 프로젝트에 추가되어 번들과 함께 전달된다. amplify libraries 가 필요로 한다.
- awsconfiguration.json: 프로젝트에 추가되어 번들과 함께 전달된다. amplify libraries 가 필요로 한다.
4. Todo Project 에서 모델 파일 생성
프로젝트 및 amplify 세팅은 끝났다. 다음은 앱이 저장할 데이터 모델을 만드는 것이다.
Amplify DataStore는 지금 만들 모델을 사용하여 추가적인 코드 작성없이 backend api에 local device 데이터를 동기화 시킨다.
이 모델을은 GraphQL이라는 스키마를 사용할 것이다.
[GraphQL은 Facebook이 만든 데이터 질의어 이다.]
AmplifyConfig 에 있는 schema.graphql 파일을 연다.
원래 있던 코드를 아래의 코드로 수정한다.
enum Priority {
LOW
NORMAL
HIGH
}
type Todo @model {
id: ID!
name: String!
priority: Priority
description: String
}
모델에 대해 간단히 설명하면
- id: 자동으로 만들어지는 identifier 역할을 하는 필드
- name: 필수 문자열 필드로 Todo 의 제목
- priority: optional enumeration 타입으로 Todo 의 우선순위를 작성하는 필드이다.
- description: Todo의 설명으로 optional String 필드이다.
그다음 이 모델을 위한 class 를 생성한다.
amplifytools.xcconfig 파일에서 modelgen=true 로 바꿔준다.
그러고 나서 프로젝트 빌드(cmd + b) 를 하면 모델에 관한 새로운 클래스들이 생성된 것을 볼 수 있다.
4. AWS Amplify 프레임워크 Todo Project 에 integration
생성된 모델을 create, update, query, delete 해볼 것이다. 그러기 위해 DataStore를 초기화 해서 Todo items를 다뤄볼 것 이다.
먼저 AppDelegate 에서 Amplify 와 DataStore를 추가한다.
import Amplify
import AmplifyPlugins
그리고 application(_ Didfinishlaunchingwithoptions:) 에 아래 코드를 작성한다.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let dataStorePlugin = AWSDataStorePlugin(modelRegistration: AmplifyModels())
do {
try Amplify.add(plugin:dataStorePlugin)
try Amplify.configure()
print("Initialized Amplify");
} catch {
print("Could not initialize Amplify: \(error)")
}
return true
}
그리고 Build 하고 실행하면 Xcode Console 에서
Initialized Amplify
추가적으로 log level의 단계를 바꾸고 싶다면 Amplify.Logging.Loglevel 변수를 사용하면된다.
예를들어 AppDelegate 의 didFinishLaunchingWithOptions에 해당 변수를 .info 로 바꾸면
실행했을 때 좀더 상세한 로그를 볼 수 있다.
이제 실제 Todo List 에 대한 메서드를 작성해 보자
ViewController 에 추가하면 된다.
DataStore 에 Todo 추가하는 코드
private func addTodo(_ title: String, _ priority: Priority,_ description: String){
let item = Todo(id: UUID().uuidString, name: title, priority: priority, description: description)
Amplify.DataStore.save(item) { result in
switch result {
case .success(let savedItem):
print("Saved Item: \(savedItem.name)")
case .failure(let error):
print("Could not save item to dataStore: \(error)")
}
}
}
DataStore 에 저장된 Todo 를 가져오는 코드
private func queryTodo() {
Amplify.DataStore.query(Todo.self, completion: { result in
switch(result) {
case .success(let todos):
for todo in todos {
print("==== Todo ====")
print("Name: \(todo.name)")
if let priority = todo.priority {
print("Priority: \(priority)")
}
if let description = todo.description {
print("Description: \(description)")
}
}
case .failure(let error):
print("Could not query DataStore: \(error)")
}
})
}
쿼리할 땐 몇가지 filter 옵션이 있다.
해당 옵션을 쓰려면 아래와 같이 where 문만 추가하면 된다.
Amplify.DataStore.query(Todo.self,
where: Todo.keys.priority.eq(Priority.high.rawValue),
completion: { result in
...생략
DataStore 에 저장된 Todo Update 하는 코드
private func updateTodo(_ title: String) {
Amplify.DataStore.query(Todo.self,
where: Todo.keys.name.eq(title),
completion: {
result in
switch (result) {
case.success(let todos):
guard todos.count == 1,
var updatedTodo = todos.first
else {
print("Did not find exactly one todo, bailing")
return
}
updatedTodo.name = "File quarterly taxes"
Amplify.DataStore.save(updatedTodo,
completion: {
result in
switch (result) {
case.success(let savedTodo):
print("Updated item: \(savedTodo.name )")
case.failure(let error):
print("Could not update data in Datastore: \(error)")
}
})
case.failure(let error):
print("Could not query DataStore: \(error)")
}
})
}
DataStore 에 저장된 Todo Delete 하는 코드
private func deleteTodo(_ title: String) {
Amplify.DataStore.query(Todo.self,
where: Todo.keys.name.eq("title"),
completion: {
result in
switch (result) {
case.success(let todos):
guard todos.count == 1,
let toDeleteTodo = todos.first
else {
print("Did not find exactly one todo, bailing")
return
}
Amplify.DataStore.delete(toDeleteTodo,
completion: {
result in
switch (result) {
case.success:
print("Deleted item: \(toDeleteTodo.name)")
case.failure(let error):
print("Could not update data in Datastore: \(error)")
}
})
case.failure(let error):
print("Could not query DataStore: \(error)")
}
})
}
7. Todo 프로젝트 AWS 에 연동
DataStore 를 통해 local 하게 데이터를 유지하는 것 까지 작성했다. 다음 단계는 해당 데이터를 클라우드와 연동하는 것 이다.
amplifytools.xcconfig 파일에서 push 를 true 로 바꿔준다.
그리고 빌드를 하게되면 amplify tool이 프로젝트에 설정된 configuration을 백엔드로 push 해준다.
몇분정도 걸릴 수 있고 xcode 로딩바에서 진행상황을 볼 수 있다.
끝나면 subcription을 추가해야 한다.
subscription 하는 이유는 백엔드에서 값이 Mutate 되었을때 로컬 DataStore 을 업데이트 해주기 위해서 이다.
(여기서 말하는 subscription은 Rx 에서 쓰이는 subscription인 것 같다.)
AppDelegate 에서 아까 작성한 Amplify init 코드에 apiPlugin을 추가하여 수정해야 한다.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
Amplify.Logging.logLevel = .info
let apiPlugin = AWSAPIPlugin(modelRegistration: AmplifyModels())
let dataStorePlugin = AWSDataStorePlugin(modelRegistration: AmplifyModels())
do {
try Amplify.add(plugin:apiPlugin)
try Amplify.add(plugin:dataStorePlugin)
try Amplify.configure()
print("Initialized Amplify");
} catch {
print("Could not initialize Amplify: \(error)")
}
return true
}
Subscribe를 Combine 으로 한다. ViewController 로 돌아와 아래 코드를 작성해 준다.
@State var todoSubscription: AnyCancellable?
func subscribeTodos() {
self.todoSubscription
= Amplify.DataStore.publisher(for: Todo.self)
.sink(receiveCompletion: { completion in
print("Subscription has been completed: \(completion)")
}, receiveValue: { mutationEvent in
print("Subscription got this value: \(mutationEvent)")
})
}
그리고 Todo 정보 업데이트가 필요한 곳에서 함수를 호출한다. (나는 viewDidLoad 에서 호출)
이제 잘 백엔드와 잘 동작되는지 테스트 해보자
Xcode 프로젝트가 있는 경로에서 터미널을 통해 아래 명령어 입력한다.
amplify console api
GraphQL 을 선택한다.
그럼 AWS AppSync Console 웹이 뜬다.
어떤 Todo 가 있는지 쿼리
query GetTodos {
listTodos {
items {
id
name
description
_deleted
}
}
}
Console 에서 Todo 아이템 추가쿼리
mutation CreateTodo {
createTodo(
input: {
name: "Tidy up the office",
description: "Organize books, vacuum, take out the trash",
priority: NORMAL
}
) {
id,
name,
description,
priority,
_version,
_lastChangedAt,
}
}
해당 쿼리를 입력한 뒤 앱을 다시켜면 subscribeTodos의 completion을 통해 정보가 받아질 것 이다.
7. Todo List UI 구성 및 앱 완성
일단 간단하게 화면 구성하고 몇가지 기능만 구현했다.
- 할일 데이터 들고와서 TableView 뿌리기
- 할일 데이터 웹에서 추가 및 삭제시 앱 새로고침 없이 데이터 갱신 (Combine)
- 할일 데이터 앱에서 추가 및 삭제시 백엔드에 반영
[앞으로 구현해야 하는 기능]
- 할일 검색
- 할일 수정
- 디자인 조금 수정
일단 완성된 앱 영상
{
"data": {
"listTodos": {
"items": [
{
"id": "3E459A7F-DEB7-4412-A846-471C5AFA0691",
"name": "할일추가 2예시",
"description": "언제 삭제 검색 수정기능만드냐",
"_deleted": null
},
{
"id": "496e6d77-9a99-41aa-a932-fe33a1eca6f7",
"name": "Tidy up the office",
"description": "Organize books, vacuum, take out the trash",
"_deleted": null
},
{
"id": "98B171A7-FDD3-4913-B6E3-590187B78ABA",
"name": "예시 할일 추가",
"description": "이것은 할일 입니다",
"_deleted": null
},
{
"id": "d1662950-fbfe-4ec3-9910-b77422cacace",
"name": "방금 추가한 할일",
"description": "Organize books, vacuum, take out the trash",
"_deleted": true
},
{
"id": "c435f16f-d336-41e3-a726-9d46919352e1",
"name": "Tidy up the office",
"description": "Organize books, vacuum, take out the trash",
"_deleted": null
},
{
"id": "02E0A22C-353E-422A-874C-D677C290CD69",
"name": "물론 앱에서도 추가하면",
"description": "백엔드에서 변경사항 볼 수있음",
"_deleted": null
},
{
"id": "eb296ced-7cba-4678-8054-e86c00a4403c",
"name": "subscription 과 콤바인으로 추가됨",
"description": "Organize books, vacuum, take out the trash",
"_deleted": true
}
]
}
}
}
이 부분의 자세한 내용은 생략하고 Github 을 통해 전체 코드 공유한다.
느낀점
iOS Native 개발자로써 Google의 Firebase 와 유사하다는 느낌이 들었다. 하지만 AWS GraphQL 과 같은 디비 뿐만이 아니라 REST API 까지 지원한다는 점에서 첫번째 차이점이 있었고 또한 AWS의 리소스를 사용하면서 AppSync 나 DynamoDB를 통해 확장이 가능한 백엔드를 구축할 수 있다는 점에서 장점이 있는 것 같다. 또한 AI/ML 과 같은 AWS 서비스를 쉽게 통합하여 구현할 수 있다는 점도 매력인 것 같다.
웹 개발자들에게 있어서는 Amplify CLI를 통해 웹앱 만들어 쉽게 배포하거나 풀스택 하이브리드앱도 지원한다는 점에서 좋을 것 같다.
AWS Amplify vs Google Firebase
댓글