AWS 시작하기

iOS 애플리케이션 구축

AWS Amplify를 사용하여 단순한 iOS 애플리케이션 생성

모듈 4: GraphQL API 및 데이터베이스 추가

이 모듈에서는 Amplify CLI와 라이브러리를 사용하여 GraphQL API를 구성하고 앱에 추가합니다.

소개

앱을 생성하고 사용자 인증으로 앱을 구성했으니 이제 API와 생성, 읽기, 업데이트, 삭제(CRUD) 작업을 데이터베이스에 추가하겠습니다.

이 모듈에서는 Amplify CLI와 라이브러리를 사용하여 앱에 API를 추가해봅니다. 여기서 생성할 API는 GraphQL API로, Amazon DynamoDB(NoSQL 데이터베이스) 기반의 AWS AppSync(관리형 GraphQL 서비스)를 활용합니다. GraphQL에 대한 자세한 소개는 이 페이지를 참조하십시오.

여기서 구축할 앱은 사용자가 메모를 작성하고 삭제하고 나열할 수 있는 메모 앱입니다. 이 예제를 통해 일반적인 유형의 CRUD+L(생성, 읽기, 업데이트, 삭제 및 나열) 애플리케이션을 구축하는 방법을 살펴볼 수 있습니다.

배우게 될 내용

  • GraphQL API 생성 및 배포
  • API와 상호 작용하는 프런트 엔드 코드 작성

주요 개념

API – 여러 소프트웨어 중개자 간의 통신과 상호 작용을 지원하는 프로그래밍 인터페이스를 제공합니다.

GraphQL – 애플리케이션의 유형이 지정된 표현을 기반으로 쿼리 언어 및 서버 측 API 구현 방식입니다. 이 API 표현 방식은 GraphQL 유형 시스템을 기반으로 한 스키마를 사용하여 선언됩니다. GraphQL에 대해 자세히 알아보려면 이 페이지를 참조하십시오.

 완료 시간

20분

 사용되는 서비스

구현

  • GraphQL API 서비스 및 데이터베이스 생성

    GraphQL API와 지원 데이터베이스를 생성하려면 터미널을 열고 프로젝트 디렉터리에서 다음 명령을 실행합니다.

    amplify add api
    
    ? Please select from one of the below mentioned services: select GraphQL and press enter
    ? Provide API name: select the default, press enter
    ? Choose the default authorization type for the API: use the arrow key to select Amazon Cognito User Pool and press enter
    ? Do you want to configure advanced settings for the GraphQL API: select the default No, I am done and press enter
    ? Do you have an annotated GraphQL schema? keep the default N and press enter
    ? What best describes your project: choose any model, we are going to replace it with our own anyway. Press enter
    ? Do you want to edit the schema now? type Y and press enter

    프로젝트를 초기화(amplify init)할 때 선택한 기본 텍스트 편집기가 열리고 미리 구축된 데이터 스키마가 표시됩니다.

    스키마를 삭제하고 앱 GraphQL 스키마로 바꿉니다.

    type NoteData
    @model
    @auth (rules: [ { allow: owner } ]) {
        id: ID!
        name: String!
        description: String
        image: String
    }

    이 데이터 모델은 NoteData 클래스 1개와 4개의 속성으로 구성됩니다. ID와 이름은 필수입니다. 설명과 이미지는 선택적 문자열입니다.

    @model 변환기는 이러한 데이터를 저장할 데이터베이스를 생성합니다.

    @auth 변환기는 이러한 데이터에 대한 액세스를 허용하는 인증 규칙을 추가합니다. 이 프로젝트에서는 NoteData의 소유자만 데이터에 액세스할 수 있습니다.

    완료되면 저장합니다.

  • 클라이언트 측 코드 생성

    Amplify는 방금 생성된 GraphQL 데이터 모델 정의에 따라 앱에서 데이터를 표시할 클라이언트 측 코드(Swift 코드)를 생성합니다.

    코드를 생성하려면 터미널에서 다음 명령을 실행합니다.

    amplify codegen models

    그러면 amplify/generated/models 디렉터리에 Swift 파일이 생성됩니다. 다음 명령을 사용하여 파일을 확인할 수 있습니다.

    ➜  iOS Getting Started git:(master) ✗ ls -al amplify/generated/models
    total 24
    drwxr-xr-x  5 stormacq  admin  160 Jul  9 14:20 .
    drwxr-xr-x  3 stormacq  admin   96 Jul  9 14:20 ..
    -rw-r--r--  1 stormacq  admin  380 Jul  9 14:20 AmplifyModels.swift
    -rw-r--r--  1 stormacq  admin  822 Jul  9 14:20 NoteData+Schema.swift
    -rw-r--r--  1 stormacq  admin  445 Jul  9 14:20 NoteData.swift

    이러한 파일을 Xcode 프로젝트로 가져옵니다. 파인더에서 파일을 찾고 Xcode의 프로젝트로 끌어서 놓습니다.

    iOSTutorial-Module4-Step1
  • API 서비스 및 데이터베이스 배포

    방금 생성한 백엔드 API와 데이터베이스를 배포하려면 터미널로 이동하여 다음 명령을 실행합니다.

    amplify push
    # press Y when asked to continue
    
    ? Are you sure you want to continue? accept the default Y and press enter
    ? Do you want to generate code for your newly created GraphQL API type N and press enter

    몇 분 후에 다음과 같은 성공 메시지가 표시됩니다.

    ✔ All resources are updated in the cloud
    
    GraphQL endpoint: https://yourid.appsync-api.eu-central-1.amazonaws.com/graphql
  • Xcode 프로젝트에 API 클라이언트 라이브러리 추가

    코드 작업을 시작하기 전에 Amplify API 라이브러리를 프로젝트의 종속성에 추가합니다. Podfile 파일을 열고 AmplifyPlugins/AWSAPIPlugin을 사용하여 해당 줄을 추가하거나 아래의 전체 파일을 복사해 붙여 넣습니다.

    # you need at least version 13.0 for this tutorial, more recent versions are valid too
    platform :ios, '13.0'
    
    target 'getting started' do
      # Comment the next line if you don't want to use dynamic frameworks
      use_frameworks!
    
      # Pods for getting started
      pod 'Amplify', '~> 1.0'                             # required amplify dependency
      pod 'Amplify/Tools', '~> 1.0'                       # allows to call amplify CLI from within Xcode
    
      pod 'AmplifyPlugins/AWSCognitoAuthPlugin', '~> 1.0' # support for Cognito user authentication
      pod 'AmplifyPlugins/AWSAPIPlugin', '~> 1.0'         # support for GraphQL API
    
    end

    터미널에서 다음 명령을 실행합니다.

    pod install

    이 명령은 완료하는 데 다소 시간이 걸립니다. 다음 명령이 표시됩니다. 실제 버전 번호는 다를 수 있습니다.

    Analyzing dependencies
    Downloading dependencies
    Installing AmplifyPlugins 1.0.4
    Installing AppSyncRealTimeClient (1.1.6)
    Installing ReachabilitySwift (5.0.0)
    Installing Starscream (3.0.6)
    Generating Pods project
    Integrating client project
    Pod installation complete! There are 4 dependencies from the Podfile and 11 total pods installed.
  • 런타임 시 Amplify 라이브러리 초기화

    Xcode로 돌아가 Backend.swift를 열고 Amplify 초기화 시퀀스의 private init() 메서드에 줄을 추가합니다. 완성된 코드 블록은 다음과 같습니다.

    // initialize amplify
    do {
       try Amplify.add(plugin: AWSCognitoAuthPlugin())
       try Amplify.add(plugin: AWSAPIPlugin(modelRegistration: AmplifyModels()))
       try Amplify.configure()
       print("Initialized Amplify")
    } catch {
       print("Could not initialize Amplify: \(error)")
    }
  • GraphQL 데이터 모델과 앱 모델 사이에 브리징 추가

    프로젝트에는 Note를 나타내는 데이터 모델이 이미 있습니다. 따라서 이 모델을 계속해서 사용하고 NoteData를 Note로 간편하게 변환하는 것이 좋습니다. ContentView.swift를 열고 Note 클래스에 이 이니셜라이저를 추가합니다.

    convenience init(from data: NoteData) {
        self.init(id: data.id, name: data.name, description: data.description, image: data.image)
     
        // store API object for easy retrieval later
        self._data = data
    }
    
    fileprivate var _data : NoteData?
    
    // access the privately stored NoteData or build one if we don't have one.
    var data : NoteData {
    
        if (_data == nil) {
            _data = NoteData(id: self.id,
                                name: self.name,
                                description: self.description,
                                image: self.imageName)
        }
    
        return _data!
    }
  • Backend 클래스에 API CRUD 메서드 추가

    API를 호출하는 3개의 메서드(Note 쿼리 메서드, 새 Note 생성 메서드 및 Note 삭제 메서드)를 추가합니다. 이러한 메서드는 앱 데이터 모델(Note)에서 작동하므로 사용자 인터페이스에서 쉽게 상호 작용할 수 있습니다. 이러한 메서드는 Note를 자동으로 GraphQL의 NoteData 객체로 변환합니다.

    Backend.swift 파일을 열고 Backend 클래스 끝에 다음 조각을 추가합니다.

        // MARK: API Access
    
        func queryNotes() {
    
            _ = Amplify.API.query(request: .list(NoteData.self)) { event in
                switch event {
                case .success(let result):
                    switch result {
                    case .success(let notesData):
                        print("Successfully retrieved list of Notes")
    
                        // convert an array of NoteData to an array of Note class instances
                        for n in notesData {
                            let note = Note.init(from: n)
                            DispatchQueue.main.async() {
                                UserData.shared.notes.append(note)
                            }
                        }
    
                    case .failure(let error):
                        print("Can not retrieve result : error  \(error.errorDescription)")
                    }
                case .failure(let error):
                    print("Can not retrieve Notes : error \(error)")
                }
            }
        }
    
        func createNote(note: Note) {
    
            // use note.data to access the NoteData instance
            _ = Amplify.API.mutate(request: .create(note.data)) { event in
                switch event {
                case .success(let result):
                    switch result {
                    case .success(let data):
                        print("Successfully created note: \(data)")
                    case .failure(let error):
                        print("Got failed result with \(error.errorDescription)")
                    }
                case .failure(let error):
                    print("Got failed event with error \(error)")
                }
            }
        }
    
        func deleteNote(note: Note) {
    
            // use note.data to access the NoteData instance
            _ = Amplify.API.mutate(request: .delete(note.data)) { event in
                switch event {
                case .success(let result):
                    switch result {
                    case .success(let data):
                        print("Successfully deleted note: \(data)")
                    case .failure(let error):
                        print("Got failed result with \(error.errorDescription)")
                    }
                case .failure(let error):
                    print("Got failed event with error \(error)")
                }
            }
        }

    동일한 Backend.swift 파일에서 updateUserData(withSignInStatus:) 메서드를 다음과 같이 업데이트합니다.

    // change our internal state, this triggers an UI update on the main thread
    func updateUserData(withSignInStatus status : Bool) {
        DispatchQueue.main.async() {
            let userData : UserData = .shared
            userData.isSignedIn = status
    
            // when user is signed in, query the database, otherwise empty our model
            if status {
                self.queryNotes()
            } else {
                userData.notes = []
            }
        }
    }

    이제, 새 Note를 생성하고 목록에서 Note를 삭제할 수 있는 사용자 인터페이스를 생성하기만 하면 됩니다.

  • Add Note에 Edit 버튼 추가

    백엔드 및 데이터 모델 조각이 준비되었으니 이 섹션의 마지막 단계로 사용자가 새 Note를 생성하고 삭제할 수 있는 기능을 제공하면 됩니다.

    Xcode에서 ContentView.swift 열기

    a. ContentView 구조체에서 사용자 인터페이스에 바인딩된 상태 변수를 추가합니다.

    // add at the begining of ContentView class
    @State var showCreateNote = false
    
    @State var name : String        = "New Note"
    @State var description : String = "This is a new note"
    @State var image : String       = "image"

    b. 파일의 아무 위치에 사용자가 새 Note를 생성할 수 있게 하는 View 구조체를 추가합니다.

    struct AddNoteView: View {
        @Binding var isPresented: Bool
        var userData: UserData
    
        @State var name : String        = "New Note"
        @State var description : String = "This is a new note"
        @State var image : String       = "image"
        var body: some View {
            Form {
    
                Section(header: Text("TEXT")) {
                    TextField("Name", text: $name)
                    TextField("Name", text: $description)
                }
    
                Section(header: Text("PICTURE")) {
                    TextField("Name", text: $image)
                }
    
                Section {
                    Button(action: {
                        self.isPresented = false
                        let noteData = NoteData(id : UUID().uuidString,
                                                name: self.$name.wrappedValue,
                                                description: self.$description.wrappedValue)
                        let note = Note(from: noteData)
    
                        // asynchronously store the note (and assume it will succeed)
                        Backend.shared.createNote(note: note)
    
                        // add the new note in our userdata, this will refresh UI
                        self.userData.notes.append(note)
                    }) {
                        Text("Create this note")
                    }
                }
            }
        }
    }

    c. Note 생성을 위한 시트를 나타내는 + 버튼을 탐색 모음에 추가합니다.

    ContentView 구조체로 돌아와서 navigationBarItems(leading SignOutButton())을 다음으로 바꿉니다.

        .navigationBarItems(leading: SignOutButton(),
                            trailing: Button(action: {
            self.showCreateNote.toggle()
        }) {
            Image(systemName: "plus")
        })
    }.sheet(isPresented: $showCreateNote) {
        AddNoteView(isPresented: self.$showCreateNote, userData: self.userData)
  • Delete 동작에 Swipe 추가

    마지막으로, ContentView에서 '밀어서 삭제' 동작을 추가합니다. .onDelete { } 메서드를 ForEach 구조체에 추가합니다.

    ForEach(userData.notes) { note in
        ListRow(note: note)
    }.onDelete { indices in
        indices.forEach {
            // removing from user data will refresh UI
            let note = self.userData.notes.remove(at: $0)
    
            // asynchronously remove from database
            Backend.shared.deleteNote(note: note)
        }
    }
  • 구축 및 테스트

    정상적으로 작동하는지 확인하기 위해 프로젝트를 빌드하고 실행합니다. 제품(Product) 메뉴에서 실행(Run)을 선택하거나 ⌘R을 입력합니다. 오류가 발생하지 않아야 합니다.

    아직 로그인되어 있다면 앱이 빈 목록에서 시작됩니다. Note를 추가할 수 있는 + 버튼이 포함되어 있습니다. + 기호를 탭하고 [이 메모 생성(Create this Note)]을 탭하면 목록에 메모가 표시됩니다.

    AddNoteView를 아래로 당겨 닫을 수 있습니다. iOS 시뮬레이터에서는 +를 두 번 탭할 수 없으므로 먼저 '당겨서 새로 고침’을 통해 목록을 새로 고쳐야 합니다.

    행을 왼쪽으로 밀어 메모를 삭제할 수 있습니다.

    전체 흐름은 다음과 같습니다.

    iOSTutorial-Module4-step2
    iOSTutorial-Module4-step3
    iOSTutorial-Module4-step4
    iOSTutorial-Module4-step5

결론

이제 iOS 앱이 생성되었습니다! AWS Amplify를 사용하여 앱에 GraphQL API를 추가하고 생성, 읽기 및 삭제 기능을 구성했습니다.

다음 모듈에서는 사진 관리를 위한 UI 및 동작을 추가합니다.

이 모듈이 유용했습니까?

감사합니다.
좋아하는 사항을 알려주세요.
닫기
실망을 드려 죄송합니다.
오래되었거나 혼란스럽거나 부정확한 사항이 있습니까? 피드백을 제공하여 이 자습서를 개선할 수 있도록 도와주십시오.
닫기

스토리지 추가