bloodlines

A go service for sending Expresso emails
Quick Start
Follow this guide if you just want to run an instance of bloodlines.
You'll need docker installed
In exampleConfig.json, modify mysql host, port, user, and password to reference your sql instance. Do the same for rabbitmq and sendgrid information.
$ docker pull ghmeier/bloodlines
$ docker run -p 8080:8080 ghmeier/bloodlines:latest
Development Setup
Follow this guide if you want to develop on bloodlines.
Install Golang
Install Docker
$ go get github.com/ghmeier/bloodlines
$ cd $GOPATH/src/github.com/ghmeier/bloodlines
$ go get github.com/tools/godep
$ go get github.com/stretchr/testify
$ godep restore
$ make deps
$ make test
After following this, you should have a bloodlines binary in the root directory. Running make run executes that binary, and your output should indicate that all tests are passing.
Now, you need a few other services to properly run bloodlines. We'll use docker to get them up and running.
$ docker run -d -p 3306:3306 -e MYSQL_PASS="soomepassword" ghmeier/expresso-mysql
$ docker run -d -p 5672:5672 ghmeier/rabbitmq-delayed
Modify exampleConfig.json to reflect the ip and port of those two instances. (Try docker ps if you're unsure).
$ mv exampleConfig.json config.json
Finally, if you want to actually send emails, you'll have to fill out the sendgrid configuration with your own account.
Now start bloodlines:
$ make run
API
Content
POST /api/content creates and adds a new content record to the database.
Example:
Request:
POST localhost:8080/api/content
{
"contentType": "EMAIL",
"text": "$greeting$ $first_name$,\n Welcome to Expresso.",
"parameters": ["first_name","greeting"]
}
Response:
{
"data": {
"id": "86c3d82d-da86-11e6-9d4c-0242ac120004",
"contentType": "EMAIL",
"text": "Hey $first_name$,\n Welcome to Expresso.",
"parameters": [
"first_name"
],
"status": "ACTIVE",
"subject": ""
}
}
GET /api/content?offset=0&limit=20 returns up to limit content records starting from offset when ordered by contentId
Example:
Request:
GET localhost:8080/api/content?offset=0&limit=20
Response:
{
"data": [
{
"id": "86c3d82d-da86-11e6-9d4c-0242ac120004",
"contentType": "EMAIL",
"text": "Hey $first_name$,\n Welcome to Expresso.",
"parameters": [
"first_name"
],
"status": "ACTIVE",
"subject": ""
}
]
}
GET /api/content/:contentId returns the content record with the given contentID
Example:
Request:
GET localhost:8080/api/content/86c3d82d-da86-11e6-9d4c-0242ac120004
Response:
{
"data": {
"id": "86c3d82d-da86-11e6-9d4c-0242ac120004",
"contentType": "EMAIL",
"text": "Hey $first_name$,\n Welcome to Expresso.",
"parameters": [
"first_name"
],
"status": "ACTIVE",
"subject": ""
}
}
PUT /api/content/:contentId updates the content record with the given contentID to match the provided data. This just overrides values, so anything not present in the request will be set to NULL
Example:
Request:
PUT localhost:8080/api/content/86c3d82d-da86-11e6-9d4c-0242ac120004
{
"id": "86c3d82d-da86-11e6-9d4c-0242ac120004",
"contentType": "EMAIL",
"text": "Hey $first_name$,\n Welcome to Expresso.",
"parameters": [
"first_name"
],
"status": "ACTIVE",
"subject": "Hello world"
}
Response:
{
"data": {
"id": "86c3d82d-da86-11e6-9d4c-0242ac120004",
"contentType": "EMAIL",
"text": "Hey $first_name$,\n Welcome to Expresso.",
"parameters": [
"first_name"
],
"status": "ACTIVE",
"subject": "Hello world"
}
}
DELETE /api/content/:contentId sets the contentStatus to INACTIVE so it won't be shown when getting all content. The data can still be accessed by getting the content object by contentId
Example:
Request:
DELETE localhost:8080/api/content/86c3d82d-da86-11e6-9d4c-0242ac120004
Response:
{
"success": true
}
Receipt
POST /api/receipt/send creates queues a message based on the given receipt data.
Example:
Request:
POST localhost:8080/api/receipt/send
{
"values": {
"greeting": "Whaddup",
"first_name": "garret"
},
"contentId": "dd82cc65-d79d-11e6-9d4c-0242ac120004",
"userId": "afee47b7-4eff-4826-a12c-86affd91a2d9"
}
Response:
{
"data": {
"id": "78b0444c-da8c-11e6-bc32-0021ccdc3511",
"ts": "2017-01-14T13:05:53.647317899-06:00",
"values": {
"first_name": "garret",
"greeting": "Whaddup"
},
"sendState": "READY",
"contentId": "dd82cc65-d79d-11e6-9d4c-0242ac120004",
"userId": "afee47b7-4eff-4826-a12c-86affd91a2d9"
}
}
GET /api/receipt returns an array of up to limit receipt records starting at the offset record when ordered by receiptID
Example:
Request:
GET localhost:8008/api/receipt?offset=0&limit=1
Response:
{
"data": [
{
"id": "7890031d-da8b-11e6-86c2-0021ccdc3511",
"ts": "2017-01-14T18:58:43Z",
"values": {
"first_name": "garret",
"greeting": "Whaddup"
},
"sendState": "FAILURE",
"contentId": "dd82cc65-d79d-11e6-9d4c-0242ac120004",
"userId": "afee47b7-4eff-4826-a12c-86affd91a2d9"
}
]
}
GET /api/receipt/:receiptId returns the receipt record with the given receiptID
Example:
Request:
GET localhost:8080/api/receipt/
Response:
{
"data": {
"id": "7890031d-da8b-11e6-86c2-0021ccdc3511",
"ts": "2017-01-14T18:58:43Z",
"values": {
"first_name": "garret",
"greeting": "Whaddup"
},
"sendState": "FAILURE",
"contentId": "dd82cc65-d79d-11e6-9d4c-0242ac120004",
"userId": "afee47b7-4eff-4826-a12c-86affd91a2d9"
}
}
Job
NOT IMPLEMENTED
Trigger
POST /api/trigger creates a new trigger with the given data.
Example:
Request:
POST localhost:8080/api/trigger
{
"values": {
"greeting": "Whaddup"
},
"tkey": "welcome",
"contentId": "dd82cc65-d79d-11e6-9d4c-0242ac120004"
}
Response:
{
"data": {{
"data": {
"id": "ca6044a6-da8d-11e6-bc32-0021ccdc3511",
"contentId": "dd82cc65-d79d-11e6-9d4c-0242ac120004",
"tkey": "welcome",
"values": {
"greeting": "Whaddup"
}
}
}
"id": "ca6044a6-da8d-11e6-bc32-0021ccdc3511",
"contentId": "dd82cc65-d79d-11e6-9d4c-0242ac120004",
"tkey": "welcome",
"values": {
"greeting": "Whaddup"
}
}
GET /api/trigger returns a list of limit trigger records starting at the offset record when they're ordered by triggerID
Example:
Request:
GET localhost:8080/api/trigger?limit=1&offset=0
Response:
{
"data": [
{
"id": "ca6044a6-da8d-11e6-bc32-0021ccdc3511",
"contentId": "dd82cc65-d79d-11e6-9d4c-0242ac120004",
"tkey": "welcome",
"values": {
"greeting": "Whaddup"
}
}
]
}
GET /api/trigger/:triggerKey returns the record for the trigger with the given triggerKey
Example:
Request:
GET localhost:8080/api/trigger/welcome
Response:
{
"data": {
"id": "ca6044a6-da8d-11e6-bc32-0021ccdc3511",
"contentId": "dd82cc65-d79d-11e6-9d4c-0242ac120004",
"tkey": "welcome",
"values": {
"greeting": "Whaddup"
}
}
}
PUT /api/trigger/:triggerKey updates the trigger record with new data. All properties will be overwritten.
Example:
Request:
PUT localhost:8080/api/trigger/welcome
{
"values": {
"greeting": "Hello there"
},
"tkey": "welcome",
"contentId": "dd82cc65-d79d-11e6-9d4c-0242ac120004"
}
Response:
{
"data": {
"id": "",
"contentId": "dd82cc65-d79d-11e6-9d4c-0242ac120004",
"tkey": "welcome",
"values": {
"greeting": "Hello there"
}
}
}
DELETE /api/trigger/:triggerKey removes the trigger record
Example:
Request:
DELETE localhost:8080/api/trigger/welcome
Response:
{
"success": true
}
POST /api/trigger/:triggerKey/activate activates a trigger, creating a new receipt, and sending content to the user provided. Items in the 'values' property will take precedence over the defaults stored in the trigger.
Example:
Request:
POST localhost:8080/api/trigger/welcome/activate
{
"values": {
"first_name": "garret"
},
"userId": "afee47b7-4eff-4826-a12c-86affd91a2d9"
}
Response:
{
"data": {
"receiptId": "ce678bf3-da8e-11e6-bc32-0021ccdc3511",
"contentId": "dd82cc65-d79d-11e6-9d4c-0242ac120004"
}
}
Preference
Example:
Request:
Response:
GET /api/preference/:userId
Example:
Request:
Response:
PATCH /api/preference/:userId
Example:
Request:
Response:
DELETE /api/preference/:userId
Example:
Request:
Response: