Cómo usar Cloud Datastore con Go

Esta página del instructivo de Bookshelf para Go indica cómo la app de muestra almacena sus datos persistentes en Google Cloud Datastore. El código de muestra para este paso proporciona ejemplos de cómo crear, leer, actualizar y borrar (CRUD) datos almacenados en Cloud Datastore.

Esta página forma parte de un instructivo de varias páginas. Para comenzar desde el principio y leer las instrucciones de configuración, visita la app de Bookshelf para Go.

Configuraciones

  1. Ve al directorio que contiene el código de muestra:

    Linux/macOS

    cd $GOPATH/src/github.com/GoogleCloudPlatform/golang-samples/getting-started/bookshelf
    

    Windows

    cd %GOPATH%\src\github.com\GoogleCloudPlatform\golang-samples\getting-started\bookshelf
    

  2. Abre config.go para editar.

  3. Borra los comentarios de esta línea:

    // DB, err = configureDatastoreDB("projectid")
    
  4. Reemplaza "projectid" por el ID de tu proyecto.

  5. Guarda y cierra config.go.

Cloud Datastore es un servicio completamente administrado que se inicializa y se conecta a la app de App Engine automáticamente. No es necesario que lo configures.

Cómo ejecutar la app en la máquina local

  1. Ejecuta la app para iniciar un servidor web local:

    cd app
    go run app.go auth.go template.go
    
  2. En el navegador web, ingresa la siguiente dirección:

    http://localhost:8080

Ahora puedes navegar por las páginas web de la app y agregar, editar y borrar libros.

Presiona Control + C para salir del servidor web local.

Cómo implementar la app en el entorno flexible de App Engine

  1. En el directorio app, ingresa el siguiente comando para implementar la muestra:

    gcloud app deploy
    
  2. En el navegador web, ingresa la siguiente dirección. Reemplaza [YOUR_PROJECT_ID] por el ID del proyecto:

    https://[YOUR_PROJECT_ID].appspot.com
    

Si actualizas tu app, podrás implementar la versión actualizada mediante el mismo comando que usaste para implementar la app por primera vez. La implementación nueva crea una versión nueva de tu app y la convierte a la versión predeterminada. Las versiones anteriores de la app se conservan, al igual que sus instancias de VM asociadas. Ten en cuenta que todas estas instancias de VM y versiones de la app son recursos facturables.

Para reducir costos, borra las versiones no predeterminadas de la app.

Para borrar una versión de una app, haz lo siguiente:

  1. En GCP Console, dirígete a la página Versiones de App Engine.

    Ir a la página de Versiones

  2. Haz clic en la casilla de verificación junto a la versión de app no predeterminada que deseas borrar.
  3. Haz clic en el botón Borrar en la parte superior de la página para borrar la versión de la app.

Para obtener toda la información acerca de la limpieza de los recursos facturables, consulta la sección Limpieza en el paso final de este instructivo.

Estructura de la aplicación

Este diagrama muestra cómo los componentes de la aplicación funcionan juntos.

Proceso y estructura de la implementación de la app de Bookshelf

Cómo comprender el código

En esta sección se explica el código de la aplicación y su funcionamiento.

Cómo manejar los envíos de los usuarios con formularios

Cuando un usuario hace clic en Add Book (Agregar libro), el navegador lo lleva a /books/add y la función addFormHandler en app/app.go muestra un formulario donde el usuario puede agregar un libro:

r.Methods("GET").Path("/books/add").
	Handler(appHandler(addFormHandler))
// addFormHandler displays a form that captures details of a new book to add to
// the database.
func addFormHandler(w http.ResponseWriter, r *http.Request) *appError {
	return editTmpl.Execute(w, r, nil)
}

Imagen de un formulario para agregar y editar

El formulario incluye campos de entrada de texto para Title (Título), Author (Autor), Date Published (Fecha de publicación) y Description (Descripción), además de otros que se utilizan en otras secciones de este instructivo.

<form method="post" enctype="multipart/form-data" action="/books{{if .}}/{{.ID}}{{end}}">
  <div class="form-group">
    <label for="title">Title</label>
    <input class="form-control" name="title" id="title" value="{{.Title}}">
  </div>
  <div class="form-group">
    <label for="author">Author</label>
    <input class="form-control" name="author" id="author" value="{{.Author}}">
  </div>
  <div class="form-group">
    <label for="publishedDate">Date Published</label>
    <input class="form-control" name="publishedDate" id="publishedDate" value="{{.PublishedDate}}">
  </div>
  <div class="form-group">
    <label for="description">Description</label>
    <input class="form-control" name="description" id="description" value="{{.Description}}">
  </div>
  <div class="form-group">
    <label for="image">Cover Image</label>
    <input class="form-control" name="image" id="image" type="file">
  </div>
  <button class="btn btn-success">Save</button>
  <input type="hidden" name="imageURL" value="{{.ImageURL}}">
  <input type="hidden" name="createdBy" value="{{.CreatedBy}}">
  <input type="hidden" name="createdByID" value="{{.CreatedByID}}">
</form>

Cómo manejar los envíos de formularios

Cuando un usuario completa el formulario Add book (Agregar libro) y luego hace clic en Save (Guardar), la función createHandler comienza el proceso de envío de los datos entregados a Cloud Datastore, pasándolo al método bookshelf.DB.AddBook:

r.Methods("POST").Path("/books").
	Handler(appHandler(createHandler))
// createHandler adds a book to the database.
func createHandler(w http.ResponseWriter, r *http.Request) *appError {
	book, err := bookFromForm(r)
	if err != nil {
		return appErrorf(err, "could not parse book from form: %v", err)
	}
	id, err := bookshelf.DB.AddBook(book)
	if err != nil {
		return appErrorf(err, "could not save book: %v", err)
	}
	go publishUpdate(id)
	http.Redirect(w, r, fmt.Sprintf("/books/%d", id), http.StatusFound)
	return nil
}

La función AddBook, definida en db_datastore.go, realiza una operación Put() para agregar los datos enviados por el usuario a la base de datos:

// AddBook saves a given book, assigning it a new ID.
func (db *datastoreDB) AddBook(b *Book) (id int64, err error) {
	ctx := context.Background()
	k := datastore.IncompleteKey("Book", nil)
	k, err = db.client.Put(ctx, k, b)
	if err != nil {
		return 0, fmt.Errorf("datastoredb: could not put Book: %v", err)
	}
	return k.ID, nil
}

Cuando el usuario hace clic en Libros, el navegador lo lleva a la página /books y el método ListBooks muestra todos los libros en el almacén de datos.

La instrucción datastore.NewQuery("Book") crea una consulta que selecciona todas las entidades donde kind es igual a "Book". Una sola app puede almacenar más de un kind en el almacén de datos. La consulta incluye .Order("Title"), que especifica que los resultados deben ordenarse alfabéticamente por título del libro.

La consulta se ejecuta mediante una llamada a GetAll, que toma el objeto de la consulta y adjunta todas las entidades mostradas al segmento books. Finalmente, se configura el campo de ID en las entidades mostradas:

// ListBooks returns a list of books, ordered by title.
func (db *datastoreDB) ListBooks() ([]*Book, error) {
	ctx := context.Background()
	books := make([]*Book, 0)
	q := datastore.NewQuery("Book").
		Order("Title")

	keys, err := db.client.GetAll(ctx, q, &books)

	if err != nil {
		return nil, fmt.Errorf("datastoredb: could not list books: %v", err)
	}

	for i, k := range keys {
		books[i].ID = k.ID
	}

	return books, nil
}
¿Te ha resultado útil esta página? Enviar comentarios: