Start using Heroku with a Postgres database and integrate it with Salesforce
Overview
The marketing home page for Heroku is at
https://www.salesforce.com/products/platform/products/heroku
Salesforce bought Heroku some time ago.
Why Heroku
Heroku provides (up to 5) free personal app websites for developers and provides a easy way to bring GitHub repositories to the public cloud. Heroku automatically scales apps running on its platform.
Heroku can be setup to automatically deploy apps to a public web server whenever there is a Git push or pull request.
Get started with Heroku
-
Click this URL to register for an account:
https://www.heroku.comPROTIP: If you’re creating an account on behalf of an organization, use a service account rather than using your own account.
-
Note: To install Heroku add-ons your account must be verified.
Toolbelt CLI Install
-
Install https://toolbelt.heroku.com/
brew install -g heroku-toolbelt
The response:
==> Downloading https://s3.amazonaws.com/assets.heroku.com/heroku-client/heroku- ######################################################################## 100.0% Initialized empty Git repository in /private/tmp/heroku-20160722-78693-1njp97z/heroku-client/.git/ Error: The `brew link` step did not complete successfully The formula built, but is not symlinked into /usr/local Could not symlink bin/heroku Target /usr/local/bin/heroku already exists. You may want to remove it: rm '/usr/local/bin/heroku' To force the link and overwrite all conflicting files: brew link --overwrite heroku To list all files that would be deleted: brew link --overwrite --dry-run heroku Possible conflicting files are: /usr/local/bin/heroku -> /usr/local/heroku/bin/heroku ==> Summary 🍺 /usr/local/Cellar/heroku/3.43.5: 992 files, 6.2M, built in 7 seconds
-
If you get the message:
Error: The `brew link` step did not complete successfully The formula built, but is not symlinked into /usr/local
Fix it by first:
brew link --overwrite --dry-run heroku
To force the link and overwrite all conflicting files:
brew link --overwrite heroku
Verify installation
-
Open a new Terminal window
-
Create a new Terminal window:
heroku login
The response:
heroku-cli: Installing CLI... 20.22MB/20.22MB Enter your Heroku credentials. Email:
-
Enter your Heroku password.
BTW, I like using 1Password to securely store and retrieve passwords.
-
Enter the password
Password (typing will be hidden):
If you got it right, you see a message such as:
Logged in as wilsonmar@gmail.com
QUESTION: Where was that installed?
PROTIP: On a Mac, the installer creates folder:*
~/.netrc
TODO: Set password for auto login.
New Instance
A new instance can be created using either on Heroku on-line (shown in this section) or in a shell script.
-
Create a new instance:
cd ~/myapp heroku create
-
Go to your Dashboard Settings to delete any instances you’re not using.
PROTIP: Like Salesforce test orgs, Heroku stay free for years if you keep to 5 apps or less.
-
To kick off deployment from GitHub, click a Heroku Button or its URL:
https://heroku.com/deploy?template=https://github.com/jamesward/heroku-connect-phone-change
The link above deploys the sample “Phone Change” app described in the Salesforce Trailhead module: Quick Start: Heroku Connect [30 mins] to sync data between a Salesforce org and a Heroku Postgres database. The author, James Ward is Director, Open Source and Engineering Engagement at Salesforce.
-
Field App Name can be left blank because Heroku generates a unique one such as “shielded-harbor-5440”. Type in a custom domain name if you own one from GoDaddy, etc.
- Select United States as the Region
- See https://devcenter.heroku.com/articles/pipelines
- Click Deploy App.
Script to create new instance
Instead of the manual approach, use my Bash script to do the equivalent of the above. It’s at:
https://github.com/wilsonmar/DevSecOps/Heroku/start.sh
-
Install heroku CLI per https://devcenter.heroku.com/articles/heroku-cli
PROTIP: The source for it is at https://github.com/heroku
-
Create in your account Home folder a file containing the HEROKU_API_KEY pair.
That file is run by the script that runs Heroku.
Here a description of its actions
- Make and cd to a folder to hold the repo.
-
Optionally, go to an established repo containing Node web.js and package.json
https://github.com/jamesward/heroku-connect-phone-change
Notice in app.json vars named “PGSSLMODE” is specified for Heroku.
package.json contains the metadata of the application name, version, the version of dependencies, and the version of NodeJs and main file under the public folder.
package-lock.json is created by the command “npm install”.*
-
Clone the repository to get it local
git clone https://github.com/jamesward/heroku-connect-phone-change --depth=1 cd heroku-connect-phone-change
There is also https://github.com/jamesward/heroku_hello_world
These are the minimal files in https://github.com/jamesward/heroku-connect-phone-change or https://github.com/jamesward/heroku_hello_world
- Procfile
- package-lock.json
- package.json
- web.js or server.js - the Node application code.
Script code to create them:
echo "web: node server.js" > Procfile echo "node_modules" > .gitignore
-
Create app in Heroku:
APP_NAME="" heroku create # or add $APP_NAME
The response contains the package name and location:
Creating app... done, ⬢ guarded-ridge-66528 https://guarded-ridge-66528.herokuapp.com/ | https://git.heroku.com/guarded-ridge-66528.git
-
For SSL configuration (which requires an upgrade to paid dynos), see https://devcenter.heroku.com/articles/git#prerequisites-install-git-and-the-heroku-cli
-
Make use of the generated Git URL:
heroku git:remote -a
Alternately:
GITHUB_REPO="https://git.heroku.com/guarded-ridge-66528.git" git remote add heroku https://git.heroku.com/evening-refuge-98240.git git push heroku master
The response:
Counting objects: 58, done. Delta compression using up to 8 threads. Compressing objects: 100% (35/35), done. Writing objects: 100% (58/58), 545.91 KiB | 60.66 MiB/s, done. Total 58 (delta 21), reused 58 (delta 21) remote: Compressing source files... done. remote: Building source: remote: remote: -----> Node.js app detected remote: remote: -----> Creating runtime environment remote: remote: NPM_CONFIG_LOGLEVEL=error remote: NODE_VERBOSE=false remote: NODE_ENV=production remote: NODE_MODULES_CACHE=true remote: remote: -----> Installing binaries remote: engines.node (package.json): 0.12.7 remote: engines.npm (package.json): unspecified (use default) remote: remote: Resolving node version 0.12.7... remote: Downloading and installing node 0.12.7... remote: Using default npm version: 2.11.3 remote: remote: -----> Restoring cache remote: Skipping cache restore (not-found) remote: remote: -----> Building dependencies remote: Installing node modules (package.json) remote: body-parser@1.18.3 node_modules/body-parser remote: ├── content-type@1.0.4 remote: ├── bytes@3.0.0 remote: ├── depd@1.1.2 remote: ├── on-finished@2.3.0 (ee-first@1.1.1) remote: ├── raw-body@2.3.3 (unpipe@1.0.0) remote: ├── http-errors@1.6.3 (setprototypeof@1.1.0, inherits@2.0.3, statuses@1.5.0) remote: ├── qs@6.5.2 remote: ├── debug@2.6.9 (ms@2.0.0) remote: ├── type-is@1.6.16 (media-typer@0.3.0, mime-types@2.1.19) remote: └── iconv-lite@0.4.23 (safer-buffer@2.1.2) remote: remote: express@4.16.3 node_modules/express remote: ├── escape-html@1.0.3 remote: ├── array-flatten@1.1.1 remote: ├── setprototypeof@1.1.0 remote: ├── content-type@1.0.4 remote: ├── cookie-signature@1.0.6 remote: ├── utils-merge@1.0.1 remote: ├── merge-descriptors@1.0.1 remote: ├── methods@1.1.2 remote: ├── path-to-regexp@0.1.7 remote: ├── range-parser@1.2.0 remote: ├── encodeurl@1.0.2 remote: ├── vary@1.1.2 remote: ├── parseurl@1.3.2 remote: ├── fresh@0.5.2 remote: ├── etag@1.8.1 remote: ├── statuses@1.4.0 remote: ├── cookie@0.3.1 remote: ├── content-disposition@0.5.2 remote: ├── serve-static@1.13.2 remote: ├── safe-buffer@5.1.1 remote: ├── depd@1.1.2 remote: ├── on-finished@2.3.0 (ee-first@1.1.1) remote: ├── finalhandler@1.1.1 (unpipe@1.0.0) remote: ├── debug@2.6.9 (ms@2.0.0) remote: ├── qs@6.5.1 remote: ├── proxy-addr@2.0.4 (forwarded@0.1.2, ipaddr.js@1.8.0) remote: ├── send@0.16.2 (ms@2.0.0, destroy@1.0.4, mime@1.4.1, http-errors@1.6.3) remote: ├── type-is@1.6.16 (media-typer@0.3.0, mime-types@2.1.19) remote: ├── accepts@1.3.5 (negotiator@0.6.1, mime-types@2.1.19) remote: └── body-parser@1.18.2 (bytes@3.0.0, http-errors@1.6.3, raw-body@2.3.2, iconv-lite@0.4.19) remote: remote: pg@4.5.7 node_modules/pg remote: ├── packet-reader@0.2.0 remote: ├── js-string-escape@1.0.1 remote: ├── pg-connection-string@0.1.3 remote: ├── buffer-writer@1.0.1 remote: ├── generic-pool@2.4.2 remote: ├── semver@4.3.6 remote: ├── pgpass@0.0.3 (split@0.3.3) remote: └── pg-types@1.13.0 (pg-int8@1.0.1, postgres-bytea@1.0.0, postgres-date@1.0.3, postgres-array@1.0.2, postgres-interval@1.1.2) remote: remote: -----> Caching build remote: Clearing previous node cache remote: Saving 2 cacheDirectories (default): remote: - node_modules remote: - bower_components (nothing to cache) remote: remote: -----> Pruning devDependencies remote: remote: -----> Build succeeded! remote: -----> Discovering process types remote: Procfile declares types -> (none) remote: Default types for buildpack -> web remote: remote: -----> Compressing... remote: Done: 11.2M remote: -----> Launching... remote: Released v3 remote: https://guarded-ridge-66528.herokuapp.com/ deployed to Heroku remote: remote: Verifying deploy... done. To https://git.heroku.com/guarded-ridge-66528.git * [new branch] master -> master
-
Instantiate 1 app server instance:
heroku ps:scale web=1
Expected response:
Scaling dynos... done, now running web at 1:Free
-
Open the app’s web page in your default browser:
heroku open
A sample URL:
https://guarded-ridge-66528.herokuapp.com/
Add-on Postgres database
To add databases, monitoring services, caching services, and queuing systems, See https://elements.heroku.com/addons Now you are going to deploy an add-on. Heroku add-ons are cloud services,
Provision a relational database by adding the Heroku Postgres add-on described at https://elements.heroku.com/addons/heroku-postgresql
- In the Heroku Dashboard, click the “Manage App” button to visit the Heroku Dashboard
- Click on your new application name (for example, guarded-ridge-66528).
- Click the Resources tab.
- In the Add-ons section search field, type “Heroku Postgres” and click the response of same name.
-
Assume the plan in the pop-up (“Hobby Dev - Free”) then click Provision.
“The addon heroku-postgresql has been installed. Check out the documentation in its Dev Center article to get started.”
NOTE: The simplicity and speed of this process belies the complexity of what just happened: You provisioned one of Heroku’s 150+ add-on services. In this case, it’s a relational database. The service is fully managed, is already running, and is now connected to your application.
Heroku typically connects a provisioned add-on to an application by setting a configuration variable that is available as a runtime environment variable within the application.
- Select the Settings tab.
-
In the “Config Vars” section, click Reveal Config Vars (Key/Value pairs):
-
DATABASE_URL = postgres://abcdvnhzwoskmf:9310494d102ba4df7de3b3fe33921de3410228045309e28ae5f98411e01033c0@ec2-184-73-199-189.compute-1.amazonaws.com:5432/det6u4itvvuivx
-
PGSSLMODE = “require”, which Heroku should have taken from the app.json file:
"env": { "PGSSLMODE": { "description": "Require SSL for Postgres", "value": "require" } }
QUESTION: What is the version of Postgres?
Set Up Trailhead Playground
-
-
From the bottom of a Trailhead module page, select your “Trailhead Playground” and click Launch.
https://resourceful-moose-263556-dev-ed.lightning.force.com/…
PROTIP: If you time out, close that screen, then return to the Trailhead Module page to login using your Salesforce Trailhead login, then Launch again.
This should open to a “Bolt Solutions” app.
-
Follow the instructions in Get Your Trailhead Playground Username and Password unit of the Trailhead Playground Management module. You’ll need your username and password to provision your Heroku Connect Add-on.
Add a new field to the Contact object:
- With the Lightning UX, click the wheel to select “Setup” for a new browser window at the Setup app.
- Click the Object Manager tab next to “Home”.
- Click the blue Contact under LABEL.
- Click Fields & Relationships.
- Click New.
-
For Data Type, scroll down to select Text, then scroll up to click Next.
Complete the New Custom Field:
- Field Label: “External Phone ID”
- Length: 10
- Field Name: External_Phone_ID
- Check “Always require a value in this field in order to save a record”
- Unique: Select “Do not allow duplicate values” Leave auto selection of “Treat “ABC” and “abc” as duplicate values (case insensitive)”
- External ID: Check “Set this field as the unique record identifier from an external system”
- Click Next.
- Check “Visible” at the heading to make the field visible to all profiles.
- Scroll down to click Next,
-
Click Save.
Notice API Name is “External_Phone_ID__c”.
We’re done with Salesforce for a while, but keep the tab handy.
Add-On Heroku Connect
Applications running on Heroku can use a number of different methods to integrate with Salesforce data, including Salesforce REST APIs. But an easier approach is to use the Heroku Connect add-on, which provides bi-directional synchronization between Salesforce and Heroku Postgres, allowing you to unify and share the data in a Heroku Postgres SQL database with the contacts, accounts, and other custom objects in a Salesforce database.
- Go back to the Heroku Dashboard, then find your application and click the management console.
- Click the Resources tab.
- In the Add-ons section search field, type “Heroku Connect” and click the response of same name.
-
In the pop-up, select the plan (“Demo Edition - Free”) then click Provision for this message:
“The addon herokuconnect has been installed. Check out the documentation in its Dev Center article to get started.””
Create Connection on Heroku
- Click “Heroku Connect” under the “Add-ons” section label for a new window.
-
Click “Setup Connection”.
Heroku Connect locates the Heroku Postgres database “salesforce” provisioned earlier.
-
Click Next.
Leave default “Production” Environment (not Sandbox nor Custom Domain).
- Click Authorize.
-
If you’re prompted, Login again with your Trailhead Playground credentials, then click “Allow”.
Set up Heroku Connect
Create a mapping between the Contact object in Salesforce and a table in the Heroku Postgres database.
TODO: Image here.
- In Heroku, click “Mappings” tab.
- Click “+ Create Mapping” button near the bottom-right.
- Press command+F to find “Contact”, then click on it.
- Under the “Database -> Salesforce” section, check “Write database updates to Salesforce using – None – as the unique identifier”
-
option and choose “External_Phone_ID__c” from the dropdown list
BLAH: Stuck here. “External_Phone_ID__c” NOT in the dropdown list for Trailhead module Quick Start: Heroku Connect
This forum post mentions
”– Add a new ‘Phone UUID’ custom field on the User standard object with the resulting API name of ‘Phone_UUID__c’. The field should be of type ‘Text’ and marked as ‘Unique’ and ‘External ID’
“Can you explain how to “Update any existing User record in your Developer Edition instance to have a value of ‘0000123442’ for the ‘Phone_UUID__c’ field.” I think this is what is tripping me up and causing me to get the following error message:
-
In the Mapped Fields section, select the following fields:
- Created Date (already checked)
- FirstName
- HomePhone
- LastName and check Index
- MobilePhone
- Name (already checked)
-
Phone
- QUESTION: Where’s External phone ???
-
Click Save.
When you’ve completed the mapping setup, the data begins synchronizing. Mapping Complete Your application is now syncing (bidirectionally) a subset of the Contact object in Salesforce with a new table in the Heroku Postgres database associated with your app.
-
When the syncing is complete, open your Heroku app in a new browser tab, by entering
http://APP_NAME.herokuapp.com (replacing APP_Name with your app name)
On the app
-
Complete the form to change a contact’s phone number using the following values, which changes an existing record in the sample database:
- First Name: Tim
- Last Name: Barr
- Email: barr_tim@grandhotels.com
- Phone: (415) 555-1212
-
Click “Update Phone Number” for the “Record updated!” message.
This should update the contact record in the Heroku Postgres database and be synced with Salesforce via Heroku Connect. So verify the updates in your Trailhead Playground:
(Syncing could take a few minutes so ensure your Trailhead Playground is updated.)
- In Salesforce Lightning UX, click the App Launcher icon and select the Sales app.
- Click the Contacts tab.
- Click Recently Viewed to select All Contacts.
- Scroll down to click Tim Barr, then click the Details tab and see that the Phone was changed from “(312) 596-1000”.
Integrating Node Applications with GitHub [1h 43m] 5 Aug 2016 by Daniel Stern covers deploying GitHub branches automatically with cloud-based deployment software Heroku, from acount sign-up to …
Other Trailhead Modules to Learn
Heroku Enterprise Basics [1 hr 10 mins] Learn the basics of how and when to use the Heroku Enterprise platform.
Salesforce & Heroku Integration [2 hrs] Learn patterns and methodology of integrating apps on Heroku with Salesforce.
Heroku Flow [1 hr] to manage continuous delivery in app development
Java App Development on Heroku [1 hr] Deploy production Java apps on Heroku.
Apex Integration Services [2 hrs] +1600
Other Topics
Heroku Shield
Heroku Agile Accelerator from AppExchange Trello
https://github.com/jamesward/heroku-buildpack-static Heroku buildpack for handling static sites and single page web apps
https://github.com/jamesward/hello-kafka-salesforce
https://github.com/jamesward/atom-heroku-tools Stores a Heroku API Access Token the user’s .netrc file
https://github.com/heroku
https://www.cncf.io/community/recorded-events/ http://bit.ly/2MpdYIk VIDEO: Setting up the Heroku git-push workflow on your Kubernetes cluster in 60 seconds with Gitkube https://www.cncf.io/wp-content/uploads/2018/06/Gitkube-CNCF-webinar-June-26-1.pdf
https://github.com/financialforcedev/orizuru Streamlined communication between Heroku dynos / other worker processes It leverages Apache Avro for schema validation and communication.
https://gabebw.com/blog/2016/06/06/how-to-host-sites-on-a-subdomain-with-heroku
https://thoughtbot.com/upcase/videos/heroku-tips-and-tricks video [subscription]
http://resources.docs.salesforce.com/rel1/doc/en-us/static/pdf/SF_Git_cheatsheet_web.pdf Git CheatSheet for Working with Private Spaces in Heroku dynos
Competitors
https://cloud.google.com/cloud-build/ https://github.com/apps/google-cloud-build Google Cloud offers the first 120 build minutes per day free
More about Salesforce
This is one of a series about Salesforce
- Salesforce Ohana (about the Salesforce company, offices, mascots, emojis, and store)
- Salesforce Glossary (of acronyms)
- Salesforce Events (Conferences, local Meetups, ) to meet people face-to-face
- Salesforce Exhibitors (at Dreamforce)
- Salesforce Onboarding (Trailhead and IDEs)
- Salesforce Offerings (Clouds, Industries, Domains, GitHub, editions, pricing, features, versions)
- Salesforce Certifications (training and exams)
- Salesforce Projects, Superbadges, and Sample Apps
- Salesforce Project Plans
- Salesforce Jobs (within Salesforce, with partners, etc.)
- Salesforce Apps (in AppExchange)
- Salesforce Alexa
- Salesforce Heroku (external apps)
- Salesforce Non-Profit support
-
Salesforce NPSP (Non-Profit Success Pack) performance (with Gatling)
- Salesforce Data Management
- Salesforce Einstein
- Salesforce Selenium (test automation)