In this article we will dig a little deeper into data modeling of the FlowStack profile. We will try to keep it simple and include some examples which could easily be converted into your real world needs.
The intended audience for this article is familiar with terms like REST and JSON. If such terms scare you off, don't worry - head on to our previous article instead - What does a customer look like.
We hope to inspire developers, integrators and business developers to create awesome plugins, integrations and even standalone products using our profile api.
The Profile as a BaaS
The profile is what you are calling a lead, a customer, a contact or a subscriber. You can create, manipulate and query profiles in FlowStack using the API, effectively using it as a backend as a service.
Data Modeling
A profile, although advertised as “schema-less”, needs a schema for validation and allowing UI (and the rest of the platform) to know which fields are available, their type etc.
Let’s assume we would only like to store the following information on profiles: email, name and interests.
The schema could look like this:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Profile",
"type": "object",
"properties": {
"email": {
"type": "string",
"description": "Email"
},
"name": {
"type": "string",
"description": "Name"
},
"interests": {
"type": "array",
"uniqueItems": true,
"items": {
"type": "string"
}
}
}
}
With the above schema we could store a profile looking like this:
{
"email": "rune@awesomecompany.com",
"name": "Rune Viem",
"interests": [
"Hunting",
"Reading"
]
}
A more complex (and interesting) schema could be created by extending the previous to add support for storing bought items (e.g. from a web shop) on the profile
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Profile",
"type": "object",
"properties": {
"email": {
"type": "string",
"description": "Email"
},
"name": {
"type": "string",
"description": "Name"
},
"interests": {
"type": "array",
"uniqueItems": true,
"items": {
"type": "string"
}
},
"transactions": {
"type": "array",
"items": {
"type": "object",
"title": "Transaction",
"properties": {
"TransactionId": {
"type": "string"
},
"TransactionDate": {
"type": "string"
},
"TransactionItems": {
"type": "array",
"items": {
"type": "object",
"title": "Item",
"properties": {
"name": {
"type": "string"
},
"price": {
"type": "float"
},
"currency": {
"type": "string"
}
}
}
}
}
}
}
}
}
Let's assume the profile from the previous example bought a MacBook Pro and an iPhone from the web shop
{
"email": "rune@awesomecompany.com",
"name": "Rune Viem",
"interests": [
"Hunting",
"Reading"
],
"transactions": [{
"TransactionId": "1110012",
"TransactionDate": "2016-08-24 22:53:00",
"TransactionItems": [{
"name": "Macbook Pro",
"price": 9995.00,
"currency": "DKK"
}, {
"name": "iPhone 6",
"price": 4995.00,
"currency": "DKK"
}]
}]
}
Nested properties are cool - when you can handle them REST
FlowStack provides a REST API through the http methods GET, POST, PUT and DELETE for manipulating profiles.
Conventions
GET retrieves profiles or specific profile
DELETE deletes profile at end point
PUT replaces profile. Partial updates can NOT be done with PUT.
POST is used for create and partial updates
Examples
For simplicity's sake the system properties (e.g. createdAt and updatedAt) are not shown in the examples.
The profile schema for the examples defines a profile as having an email address, a name and transactions. A transaction has a property for telling which store (Store) the transaction was made, a property for the sales representative responsible for the transaction (Sales Contact) and the products (transactionlines) bought. The products are defined by a name (Product name) and a color (Color). Please bear with us, it's a rather simple schema - otherwise this article would be extremely long. By now you should already know enough to model your own.
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Profile",
"type": "object",
"properties": {
"email": {
"type": "string",
"description": "Email"
},
"name": {
"type": "string",
"description": "Name"
},
"transactions": {
"type": "array",
"items": {
"type": "object",
"title": "Transaction",
"properties": {
"Store": {
"type": "string"
},
"Sales Contact": {
"type": "string"
},
"transactionlines": {
"type": "array",
"items": {
"type": "object",
"title": "Item",
"properties": {
"Product name": {
"type": "string"
},
"Color": {
"type": "string"
}
}
}
}
}
}
}
}
}
Assume we have following resource at /profile/someid
{
"id": "someid",
"name": "Rune Viem"
}
PUT /profile/someid
{
"email": "rune@awesomecompany.com"
}
results in
{
"id": "someid",
"email": "rune@awesomecompany.com"
}
Resource has been REPLACED
To achieve a resource looking like this
{
"id": "someid",
"name": "Rune Viem",
"email": "rune@awesomecompany.com"
}
You need to either provide all properties (could mean you need to do a GET to retrieve those properties and values) and send via PUT e.g.
PUT /profile/someid
{
"name": "Rune Viem",
"email": "rune@awesomecompany.com"
}
or do a partial update via POST
POST /profile/someid
{
"email": "rune@awesomecompany.com"
}
Assuming the profile looked like this before
{
"id": "someid",
"name": "Rune Viem"
}
which will leave existing properties as is if they are not targeted for update (included in the payload)
Adding to a subresource (nested property on the profile) e.g. Transactions via POST
POST /profile/someid/transactions
{
"Store": "CPH",
"Sales Contact": "Simon Galschiøt",
"transactionlines": [
{
"Product name": "Pillow",
"Color": "Green"
}
]
}
could result in
{
"id": "someid",
"name": "Rune Viem",
"email": "rune@awesomecompany.com",
"transactions": [
{
"id": "sometransactionid",
"Store": "CPH",
"Sales Contact": "Simon Galschiøt",
"transactionlines": [
{
"id": "somelineid",
"Product name": "Pillow",
"Color": "Green"
}
]
}
]
}
which could of course also be achieved by using PUT on profile resource containing full profile
PUT /profile/someid
{
"name": "Rune Viem",
"email": "rune@awesomecompany.com",
"transactions": [
{
"Store": "CPH",
"Sales Contact": "Simon Galschiøt",
"transactionlines": [
{
"Product name": "Pillow",
"Color": "Green"
}
]
}
]
}
Adding another transaction line under sometransactionid
POST /profile/someid/transactions/sometransactionid/transactionlines
{
"Product Name": "Couch",
"Color": "Red"
}
which would result in
{
"id": "someid",
"name": "Rune Viem",
"email": "rune@awesomecompany.com",
"transactions": [
{
"id": "sometransactionid",
"Store": "CPH",
"Sales Contact": "Simon Galschiøt",
"transactionlines": [
{
"id": "somelineid",
"Product name": "Pillow",
"Color": "Green"
},
{
"id": "someotherlineid",
"Product name": "Couch",
"Color": "Red"
}
]
}
]
}
Updating a sub resource (transactionline) using PUT
PUT /profile/someid/transactions/sometransactionid/transactionlines/somelineid
{
"Color": "Yellow"
}
results in the profile looking like this
{
"id": "someid",
"name": "Rune Viem",
"email": "rune@awesomecompany.com",
"transactions": [
{
"id": "sometransactionid",
"Store": "CPH",
"Sales Contact": "Simon Galschiøt",
"transactionlines": [
{
"id": "somelineid",
"Color": "Yellow"
},
{
"id": "someotherlineid",
"Product name": "Couch",
"Color": "Red"
}
]
}
]
}
Doing another update on same transactionline
PUT /profile/someid/transactions/sometransactionid/transactionlines/somelineid
{
"Product": "Pillow",
"Color": "Yellow"
}
results in the profile looking like this
{
"id": "someid",
"name": "Rune Viem",
"email": "rune@awesomecompany.com",
"transactions": [
{
"id": "sometransactionid",
"Store": "CPH",
"Sales Contact": "Simon Galschiøt",
"transactionlines": [
{
"id": "somelineid",
"Product": "Pillow",
"Color": "Yellow"
},
{
"id": "someotherlineid",
"Product name": "Couch",
"Color": "Red"
}
]
}
]
}
Updating the same transactionline with POST
POST /profile/someid/transactions/sometransactionid/transactionlines/somelineid
{
"Color": "Red"
}
Result is
{
"id": "someid",
"name": "Rune Viem",
"email": "rune@awesomecompany.com",
"transactions": [
{
"id": "sometransactionid",
"Store": "CPH",
"Sales Contact": "Simon Galschiøt",
"transactionlines": [
{
"id": "somelineid",
"Product name": "Pillow",
"Color": "Red" // Partial update of this attribute only
},
{
"id": "someotherlineid",
"Product name": "Couch",
"Color": "Red"
}
]
}
]
}
Updating a transaction
Using PUT (replaces the whole targeted transaction object/resource)
PUT /profile/someid/transactions/sometransactionid
{
"Store": "London",
"Sales Contact": "John Doe",
"transactionlines": [
{
"Product name": "Shoe"
}
]
}
Results in profile looking like
{
"id": "someid",
"name": "Rune Viem",
"email": "rune@awesomecompany.com",
"transactions": [
{
"id": "someothertransactionid",
"Store": "London",
"Sales Contact": "John Doe",
"transactionlines": [
{
"id": "someotherotherlineid",
"Product name": "Shoe"
}
]
}
]
}
Doing a POST to same transaction (simple partial update without nested properties)
POST /profile/someid/transactions/sometransactionid
{
"Sales Contact": "Jane Doe",
}
Results in profile looking like
{
"id": "someid",
"name": "Rune Viem",
"email": "rune@awesomecompany.com",
"transactions": [
{
"id": "someothertransactionid",
"Store": "London",
"Sales Contact": "Jane Doe",
"transactionlines": [
{
"id": "someotherotherlineid",
"Product name": "Shoe"
}
]
}
]
}
If a POST to a sub resource includes contents of a nested resource, the nested resource will be replaced as you have explicitly set the contents of the nested resource
E.g.
POST /profile/someid/transactions/sometransactionid
{
"Sales Contact": "John Doe",
"transactionlines": [
{
"Product name": "Shoe",
"Color": "Black"
}
]
}
will result in profile looking like this
{
"id": "someid",
"name": "Rune Viem",
"email": "rune@awesomecompany.com",
"transactions": [
{
"id": "someothertransactionid",
"Store": "London",
"Sales Contact": "John Doe",
"transactionlines": [
{
"id": "someotherotherotherlineid", // new resource created (replaced)
"Product name": "Shoe",
"Color": "Black"
}
]
}
]
}
Using your own id's (actually pretty cool)
FlowStack will generate system id's for profiles when they are created. You have the possibility to set those id's yourself when you create profiles. This could be very convenient for some of you as it eliminates the need for lookup on other field/property before retrieving profile.
Querying (even cooler)
The profile API is not just for retrieving, creating, updating and deleting profiles by id's.
We created a language, SegQL, allowing you to query your profiles collection like you would query a database.
Segmentation and querying profiles will be the topic of a future article.
Here you go
By now you should know the basics of the FlowStack Profile API, which enables you to connect the dots from your various data silos into our Customer Data Platform which would benefit your marketers greatly.
We would love to hear from you, if you have interesting use cases and integrations you would like to discuss.
Visit us at FlowStack and sign up for updates on the development of the Next Gen Marketing Automation Platform.
Knock yourself out: Create - don't just build