Introducción a AWS

Crear una aplicación iOS

Crear una aplicación iOS sencilla con AWS Amplify

Módulo 4: agregar una API de GraphQL y base de datos

En este módulo usará las CLI y bibliotecas de Amplify para configurar y agregar la API de GraphQL a su aplicación.

Introducción

Ahora que hemos creado y configurado la aplicación con autenticación de usuario, agreguemos una API y operaciones de crear, leer, actualizar, eliminar (CRUD) en una base de datos.

En este módulo, agregará una API a la aplicación mediante la CLI y las bibliotecas de Amplify. La API que creará es una API GraphQL que aprovecha AWS AppSync (un servicio de GraphQL administrado) que está respaldado por Amazon DynamoDB (una base de datos de NoSQL). Para obtener una introducción a GraphQL, visite esta página.

La aplicación que creará es para tomar notas que permite a los usuarios crear, eliminar y enumerar notas. Este ejemplo otorga una buena idea de cómo crear muchos tipos de aplicaciones CRUD+L (crear, leer, actualizar, eliminar y enumerar) populares.

Lo que aprenderá

  • Crear e implementar una API de GraphQL
  • Escribir un código front-end para interactuar con la API

Conceptos clave

API: proporciona una interfaz de programación que permite la comunicación y las interacciones entre diversos intermediarios de software.

GraphQL: una implementación de API del lado del servidor e idioma de consulta basada en una representación tipada de su aplicación. Esta representación de API se declara utilizando un esquema basado en el sistema de tipo GraphQL. (Para obtener más información GraphQL, visite esta página).

 Tiempo de realización

20 minutos

 Servicios utilizados

Implementación

  • Crear un servicio y una base de datos de API GraphQL

    Para crear la API GraphQL y su base de datos de respaldo, abra una Terminal y ejecute este comando desde el directorio de su proyecto.

    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

    El editor de texto predeterminado que elige cuando inicializa el proyecto (amplify init) se abre con un esquema de datos creado previamente.

    Elimine el esquema y reemplácelo con nuestro esquema GraphQL de aplicación.

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

    El modelo de datos se compone de una clase NoteData y cuatro propiedades: el ID y el nombre son obligatorios mientras que la descripción y la imagen son cadenas opcionales.

    El transformador @model indica que queremos crear una base de datos para almacenar los datos.

    El transformador @auth agrega reglas de autenticación para permitir el acceso a estos datos. Para este proyecto, queremos que solo el propietario de NoteData tenga acceso a ellos.

    Una vez hecho esto, no olvide guardar.

  • Generar código del lado del cliente

    En función de la definición del modelo de datos GraphQL que acabamos de crear, Amplify genera código del lado del cliente (es decir, código Swift) para representar los datos en nuestra aplicación.

    Para generar el código, en su terminal, ejecute el siguiente comando:

    amplify codegen models

    Esto crea archivos Swift en el directorio amplify/generated/models, como puede ver con:

    ➜  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

    Guarde estos archivos en su proyecto Xcode: ubíquelos en el buscador y arrástrelos y suéltelos en el proyecto en Xcode.

    iOSTutorial-Module4-Step1
  • Implementar la base de datos y el servicio de la API

    Para implementar la API de backend y la base de datos que acabamos de crear, diríjase a su terminal y ejecute el comando:

    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

    Luego de unos minutos, debería ver un mensaje de éxito:

    ✔ All resources are updated in the cloud
    
    GraphQL endpoint: https://yourid.appsync-api.eu-central-1.amazonaws.com/graphql
  • Agregar biblioteca de cliente de API al proyecto de Xcode

    Antes de ir al código, agregue la biblioteca de API de Amplify a las dependencias de su proyecto. Abra el archivo Podfile y agregue la línea con AmplifyPlugins/AWSAPIPlugin o copie/pegue el archivo completo a continuación.

    # 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

    En una terminal, ejecute el comando:

    pod install

    El comando tarda unos minutos en completarse. Debería ver esto (los números de versión reales pueden variar):

    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.
  • Iniciar bibliotecas de Amplify en el tiempo de ejecución

    En Xcode, abra Backend.swift y agregue una línea en la secuencia de inicialización de Amplify en el método init() privado. El bloque de código completo debería verse así:

    // 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)")
    }
  • Agregar vínculos entre el modelo de datos GraphQL y el modelo de la aplicación

    Nuestro proyecto ya tiene un modelo de datos para representar una nota. Por lo tanto, tomé la decisión de diseño de seguir usando ese modelo y proporcionar una manera fácil de convertir un NoteData en Note. Abra ContentView.swift y agregue este inicializador en la clase 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!
    }
  • Agregar métodos API CRUD a la clase Backend

    Agreguemos tres métodos para llamar a la API: un método para consultar el Note, un método para crear un nuevo Note y un método para eliminar el Note. Tenga en cuenta que estos métodos funcionan en el modelo de datos de la aplicación (Note) a fin de facilitar la interacción desde la interfaz de usuario. Estos métodos convierten de forma transparente a Note en objetos de NoteData de GraphQL.

    Abra el archivo Backend.swift y agregue el siguiente fragmento al final de la clase 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)")
                }
            }
        }

    En el mismo archivo Backend.swift, actualice el método updateUserData(withSignInStatus:) para que se vea así:

    // 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 = []
            }
        }
    }

    Ahora, solo queda crear una parte de la interfaz de usuario para crear un nuevo Note y eliminar un Note de la lista.

  • Agregar un botón de editar para agregar una nota

    Ahora que las partes del backend y del modelo de datos están en su lugar, el último paso de esta sección es permitir a los usuarios crear nuevos Note y eliminarlos.

    En Xcode, abra ContentView.swift.

    a. En la estructura ContentView, agregue variables de estado vinculadas a la interfaz de usuario.

    // 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. En cualquier lugar del archivo, agregue una estructura de vista para permitir al usuario crear una nueva nota:

    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. Agregue un botón “+” en la barra de navegación con el fin de presentar una hoja para crear una nota.

    En la estructura ContentView, reemplace navigationBarItems(leading SignOutButton()) con

        .navigationBarItems(leading: SignOutButton(),
                            trailing: Button(action: {
            self.showCreateNote.toggle()
        }) {
            Image(systemName: "plus")
        })
    }.sheet(isPresented: $showCreateNote) {
        AddNoteView(isPresented: self.$showCreateNote, userData: self.userData)
  • Agregar un comportamiento de deslizar para eliminar

    Por último, en ContentView, agregue el comportamiento “deslizar para eliminar”: agregue el método .onDelete { } a la estructura 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)
        }
    }
  • Crear y probar

    Para verificar que todo funcione como se espera, cree y ejecute el proyecto. Haga clic en el menú Product (Producto) y seleccione Run (Ejecutar) o presione ⌘R. No debería haber ningún error.

    La aplicación comienza en la lista vacía, si asume que su sesión aún sigue abierta. Ahora tiene un botón “+” para agregar una nota. Toque el signo “+” y Create this Note (Crear esta nota) y la nota debería aparecer en la lista.

    Puede cerrar AddNoteView deslizándolo hacia abajo. Tenga en cuenta que, en el simulador de iOS, no es posible tocar “+” por segunda vez, primero debe “deslizar para actualizar” la lista.

    Puede eliminar una nota si desliza una fila hacia la izquierda.

    Este es el flujo completo.

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

Conclusión

¡Ha creado una aplicación iOS! Mediante AWS Amplify, agregó una API de GraphQL y configuró una funcionalidad para crear, leer y eliminar en su aplicación.

En el siguiente módulo, agregaremos una interfaz de usuario y comportamientos para administrar imágenes.

¿Este módulo le resultó útil?

Gracias
Indíquenos lo que le gustó.
Cerrar
Lamentamos haberlo decepcionado
¿Hay información desactualizada, confusa o inexacta? Ayúdenos a mejorar este tutorial con sus comentarios.
Cerrar

Agregar almacenamiento