Habitualmente, al insertar un valor en el backend a través de la API, si la operación tiene éxito, se devuelve el identificador del registro creado.

En el tutorial de Jeremy Morgan Building a Web App with Go and SQLite, se devuelve un mensaje genérico {"message": "success"}, que no permite realizar acciones adicionales sobre el nuevo registro.

En esta entrada modificamos el código de la función AddPerson para devolver el identificador del nuevo registro.

Empezamos definiendo la variable que contendrá el identificador del nuevo registro:

  // pId stores the autoincremental id provided by the database
  // when a new record is inserted. We initialize to 0 which, in
  // general, is not a valid id.
  var pId int64 = 0

Más adelante veremos porqué es necesario definirlo como int64 y no como int genérico.

En la línea 98 del código original del tutorial, observamos como al ejecutar el statament, se ignora uno de los valores devueltos:

_, err = stmt.Exec(newPerson.FirstName, newPerson.LastName, newPerson.Email, newPerson.IpAddress)

Revisando la documentación, Stmt.Exec devuelve Result, que es un interface que define LastInsertId(), que es justo lo que necesitamos:

// LastInsertId returns the integer generated by the database
// in response to a command. Typically this will be from an
// "auto increment" column when inserting a new row. Not all
// databases support this feature, and the syntax of such
// statements varies.
LastInsertId() (int64, error)
...

Como vemos, LastInsertId() devuelve int64, no int, por lo que la variable pId debe ajustarse a este tipo específico.

Modificamos el código original para recuperar este valor devuelto al ejecutar el statement:

  // The stmt.Exec() returns an `sql.Result`, that is an interface with 2 functions
  r, err := stmt.Exec(p.FirstName, p.LastName, p.Email, p.IPAddress)
  if err != nil {
    log.Printf("[error] error executing statement: %s", err.Error())
    return pId, err
  }
  // We retrieve the id of the inserted record using the LastInsertId() interface
  pId, err = r.LastInsertId()
  if err != nil {
    log.Printf("[error] unable to retrieve new records'Id: %s", err.Error())
  }
  tx.Commit()
  return pId, nil

Si todo ha funcionado correctamente, devolvemos el identificador del nuevo registro (y nil).

El código de la función addPerson del tutorial espera que models.AddPerson devuelva bool, error. Sin embargo, ahora devuelve el identificador del nuevo registro, así que tenemos que actualizar también el código de AddPerson:

En mi caso, he movido AddPerson al paquete handlers, por lo que la A es mayúscula para que la función se exporte.

newId, err := models.AddPerson(json)

Si se ha producido algún error al insertar el nuevo registro, en vez de false, ahora devolvemos 0, que no es un valor de identificador válido.

El código queda:

 // This version of the models.AddPerson function return the newID of
 // the record inserted (the old version just returned a bool value)
 // When there's a problem inserting the record, we return 0
 if newId != 0 {
  c.JSON(http.StatusOK, gin.H{"message": newId})
 } else {
  c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
 }

Resultado del cambio

Al insertar un nuevo registro en el backend, la API devuelve el Id del registro insertado (en vez del mensaje genérico {"message":"success"}):

$ curl -X POST localhost:8080/api/v1/person -d '{"first_name": "Fernando", "last_name": "Alonso", "email": "f.alonso@example.it", "ip_address": "localhost"}'
{"message":1004}

Podemos usar el identificador del nuevo registro creado para comprobar que, efectivamente, se ha creado la entrada con la información proporcionada, por ejemplo:

$ curl http://localhost:8080/api/v1/person/1004
{"data":[
  {"id":1004,"first_name":"Fernando","last_name":"Alonso","email":"f.alonso@example.it","ip_address":"localhost"}
]}

Conclusión

Al devolver el identificador del registro recién creado, nuestra API se vuelve más amigable para el usuario.

Con la versión original del código, no es posible encontrar el nuevo registro insertado, ya que la API sólo permite localizarlo a través del Id (mediante getPersonById).

Ahora disponemos del identificador del registro creado y podemos realizar acciones adicionales sobre el mismo.