Esta es la biblioteca oficial de Go para enviar notificaciones con la API REST de Courier.
Para obtener una descripción completa de las cargas útiles y propiedades de solicitudes y respuestas, consulte los documentos oficiales de Courier API.
Este módulo requiere la versión Go >= 1.13.
Ejecute el siguiente comando para usar la biblioteca Go en su módulo Go:
go get github.com/trycourier/courier-go/v3
import (
"context"
"fmt"
courierclient "github.com/trycourier/courier-go/v3/client"
option "github.com/trycourier/courier-go/v3/option"
)
client := courierclient . NewClient (
option . WithAuthorizationToken ( "" ),
)
import ( "context" "fmt" courier "github.com/trycourier/courier-go/v3" courierclient "github.com/trycourier/courier-go/v3/client" option "github.com/trycourier/courier-go/v3/option" ) client := courierclient . NewClient ( option . WithAuthorizationToken ( "" ), ) sendResponse , err := client . Send ( context . TODO (), & courier. SendMessageRequest { Message : courier. NewMessageFromTemplateMessage ({ Template : "" , }), }, ) if err != nil { return err } fmt . Printf ( "Sent message %s n " , sendResponse . RequestId )
Nuestra API, particularmente el método de envío, utiliza varias uniones. Nuestro Go SDK define estructuras para construir estas uniones, como courier.Message
, que se muestra a continuación:
import (
courier "github.com/trycourier/courier-go/v3"
)
request := & courier. SendMessageRequest {
// Construct a content message.
Message : & courier. Message {
ContentMessage : & courier. ContentMessage {
// Construct a single recepient that is a user recepient.
To : & courier. MessageRecipient {
Recipient : & courier. Recipient {
UserRecipient : & courier. UserRecipient {
Email : courier . String ( "[email protected]" ),
Data : & courier. MessageData {
"name" : "Marty" ,
},
},
},
},
// Construct content from elemental content sugar.
Content : & courier. Content {
ElementalContentSugar : & courier. ElementalContentSugar {
Title : "Back to the Future" ,
Body : "Oh my {{name}}, we need 1.21 Gigawatts!" ,
},
},
},
},
}
Introdujimos una mejor experiencia de construcción de uniones en 3.0.8. Por ejemplo, el tipo courier.Message
se construyó previamente con lo siguiente:
import (
courier "github.com/trycourier/courier-go/v3"
)
request := courier. SendMessageRequest {
// Construct a content message.
Message : courier . NewMessageFromContentMessage (
& courier. ContentMessage {
// Construct a single recepient that is a user recepient.
To : courier . NewMessageRecipientFromRecipient (
courier . NewRecipientFromUserRecipient (
& courier. UserRecipient {
Email : courier . String ( "[email protected]" ),
Data : & courier. MessageData {
"name" : "Marty" ,
},
},
),
),
// Construct content from elemental content sugar.
Content : courier . NewContentFromElementalContentSugar (
& courier. ElementalContentSugar {
Title : "Back to the Future" ,
Body : "Oh my {{name}}, we need 1.21 Gigawatts!" ,
},
),
},
),
}
Aunque la construcción parece bastante similar, el enfoque anterior requería navegar por una variedad de nombres de funciones de constructor engorrosos (por ejemplo, courier.NewContentFromElementalContentSugar
).
El nuevo enfoque elimina por completo a estos constructores, lo que simplifica significativamente la experiencia. Migrar desde el enfoque anterior es tan simple como establecer el tipo concreto en el campo apropiado, así:
Antes
...
Content : courier . NewContentFromElementalContentSugar (
& courier. ElementalContentSugar {
Title : "Back to the Future" ,
Body : "Oh my {{name}}, we need 1.21 Gigawatts!" ,
},
),
...
Después
...
Content : & courier. Content {
ElementalContentSugar : & courier. ElementalContentSugar {
Title : "Back to the Future" ,
Body : "Oh my {{name}}, we need 1.21 Gigawatts!" ,
},
},
...
Establecer un tiempo de espera para cada solicitud individual es tan simple como usar la biblioteca context
estándar. Configurar un tiempo de espera de un segundo para una llamada API individual se parece a lo siguiente:
ctx , cancel := context . WithTimeout ( context . TODO (), time . Second )
defer cancel ()
response , err := client . Send (
ctx ,
& courier. SendMessageRequest {
Message : ...
},
)
Se incluye una variedad de opciones de cliente para adaptar el comportamiento de la biblioteca, lo que incluye configurar tokens de autorización para enviarlos en cada solicitud o proporcionar su propio *http.Client
instrumentado. Ambas opciones se muestran a continuación:
client := courierclient . NewClient (
option . WithAuthorizationToken ( "" ),
option . WithHTTPClient (
& http. Client {
Timeout : 5 * time . Second ,
},
),
)
Se recomienda proporcionar su propio
*http.Client
. De lo contrario, se utilizaráhttp.DefaultClient
y su cliente esperará indefinidamente una respuesta (a menos que se utilice el tiempo de espera basado en contexto por solicitud).
Los tipos de error estructurados se devuelven a partir de llamadas API que devuelven códigos de estado de no éxito. Por ejemplo, puede verificar si el error se debió a una solicitud incorrecta (es decir, código de estado 400) con lo siguiente:
response , err := client . Send (
context . TODO (),
& courier. SendMessageRequest {},
)
if err != nil {
if apiErr , ok := err .( * core. APIError ); ok && apiErr . StatusCode == http . StatusBadRequest {
// Do something with the bad request ...
}
return err
}
Estos errores también son compatibles con las API errors.Is
y errors.As
, por lo que puede acceder al error de esta manera:
response , err := client . Send (
context . TODO (),
& courier. SendMessageRequest {},
)
if err != nil {
var apiErr * core. APIError
if errors . As ( err , apiError ); ok {
switch apiErr . StatusCode {
case http . StatusBadRequest :
// Do something with the bad request ...
}
}
return err
}
Si desea envolver los errores con información adicional y aún conservar la capacidad de acceder al tipo con errors.Is
y errors.As
, puede usar la directiva %w
:
response , err := client . Send (
context . TODO (),
& courier. SendMessageRequest {},
)
if err != nil {
return fmt . Errorf ( "failed to list employees: %w" , err )
}
Si bien valoramos las contribuciones de código abierto a este SDK, esta biblioteca se genera mediante programación. Las adiciones realizadas directamente a esta biblioteca tendrían que trasladarse a nuestro código de generación; de lo contrario, se sobrescribirían en la siguiente versión generada. Siéntase libre de abrir un PR como prueba de concepto, pero sepa que no podremos fusionarlo tal como está. ¡Sugerimos abrir un problema primero para discutirlo con nosotros!
Por otro lado, ¡las contribuciones al README siempre son bienvenidas!