A common use case for cartridges is to retrieve data from outside sources, and our cartridge is no different. Today, we are going to add a random dad joke below our magic gif because, well, nothing captures the essence of magic like a good dad joke, does it?
Creating a Service
The Services Framework helps us manage calls to external web services and analyze their performance. It is a site-wide setting and is accessible from the Administration section of the Business Manager. A service definition, which is how we describe and set a service within the Services framework, usually consists of 3 parts: Credentials, Profile, and Service, however in some use cases, the credentials and/or profile parts can be omitted (we will see such a scenario on day 7).
Let’s go ahead and create our dad joke service:
- Open your Business Manager and navigate to Administration > Operations >Services.
- Click on the Credentials tab and then New.
- Credentials enable us to set the URL (and, if needed, authentication details) for our service. Set the URL to https://icanhazdadjoke.com/ and name our credentials
MagicCatridge.Dad.Credentials
. Click Apply__ to save.**
icanhazdadjoke FTW!
Next, we will create a profile for our service. The profile enables us to configure connection related settings to our service, such as timeout and rate-limiting.
- Click on the Profiles tab and then New.
- Name the new profile
MagicCartridge.Dad.Profile
and set its connection timeout to 500. This will ensure that if we cannot connect to the service within 500ms, the connection will be dropped. Click Apply.
Finally, let’s create the service itself. Service is where we combine all of the settings for a service, such as its type, status (live/disabled), mode, etc.
- Click on the Services tab and then New.
- Set the following:
- Name the service
MagicCartridge.Dad.Service
. - Check the
Enabled
checkbox. - Set the profile to
MagicCartridge.Dad.Profile
. - Set the credentials to
MagicCartridge.Dad.Credentials
.
Click Apply to save.
Our new Dad service! ❤️
This concludes our dad joke service configuration. But since nothing uses it yet, it’s sitting all alone in the dark waiting for a purpose in life. We will fix this issue next.
Initializing the Dad Joke Service
Just like many things in life, before we can use our new dad joke service in the cartridge, we have to initialize it. All of our initialization logic will be handled in a single file, dadjokeservice.js
, created under a services folder within our cartridge:
- cd to the root of the MagicCartridge folder (
cd cartridges/magicCartridge/cartridge
), and create a new folder namedservices
. - Inside the new
services
folder, create a new file calleddadjokeservice.js
and add the following content:
var LocalServiceRegistry = require('dw/svc/LocalServiceRegistry');
var dadJokeAPIService = LocalServiceRegistry.createService('MagicCartridge.Dad.Service', {
createRequest: function (svc, params) {
svc.setRequestMethod('GET');
svc.addHeader('Accept', 'application/json');
return params;
},
parseResponse: function (svc, httpClient) {
var result;
try {
result = JSON.parse(httpClient.text);
} catch (e) {
result = httpClient.text;
}
return result;
}
});
module.exports = {
dadJokeAPIService: dadJokeAPIService
}
So what are we seeing here?
Line 1: Imports the LocalServiceRegistery
module, which is the base class for creating services.
Line 3: Creates an instance of the MagicCartridge.Dad.Service
we previously defined and saves it to the dadJokeAPIService
variable.
Lines 4–8: Defines a createRequest
method, which allows you to set different properties related to the service. In our example, we set the service method always to be GET
(line 5) and to always have an Accept
header of application/json
(line 6). We end the method by returning the params
object (line 7).
🐘 There are plenty of properties we can set on the svc object other then headers and method. Refer to Salesforce Commerce Cloud docs for more information.
Lines 9–18: Defines a parseResponse
method, which allows you to get the raw response of the service call, and parse or manipulate it to your needs. In our example, we try to parse the service call response (httpClient.text
) to JSON (line 13) and save that to the result
variable. If we fail (for example, we got a bad response, etc.) we will save the raw service call response to the result
variable (line 15). We end the method by returning the result
variable (line 17).
Lines 21–23: Exports the dadJokeAPIService
object.
Using the Dad Joke Service
To display the result of our service call using the Magic template, we have to call the service on the Magic controller and pass the result to the Magic template on the pipeline dictionary (pdict
).
First, let’s modify our Magic.js
controller to use the dad joke service:
var server = require('server');
var service = require('magicCartridge/cartridge/services/dadjokeservice');
server.get('Show', function (req, res, next) {
var properties = {};
var template = 'magic';
var svcResult = service.dadJokeAPIService.call();
if (svcResult.status === 'OK') {
properties.joke = svcResult.object.joke;
}
res.render(template, properties);
next();
});
module.exports = server.exports();
Can you spot the changes from yesterday’s version?
Line 2: Imports the Dad joke service and sets the service
variable to reference it.
Line 5: Defines an empty properties object.
Line 8: Uses the service
object’s call
method to make the actual call to the icanhazdadjoke.com service and store its result with the svcResult
variable.
Lines 9–11: If the service call was successful, the svcResult
’s object
property will hold the JSON response from the service. This JSON response contains a joke
property that holds the actual joke. We will save that property to a new property on our properties
object called joke
.
Line 13: Calls the render method of the res
object, passing it the properties
object we created on line 5. This object can later be used in an ISML template when it renders. To call this object in an ISML template we will use the pdict
global object. We will see how to use pdict
next.
Updating the Template
With all the backend stuff behind us, its time to update the Magic cartridge’s ISML template to actually display the joke.
- cd to the
templates/default
folder of our cartridge and open themagic.isml
file. - Change the code as follows:
<iscontent type="text/html" charset="UTF-8" compact="true"/>
<!doctype html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Magic!</title>
<style>
.mainDiv {
width:100%;
max-width:800px;
margin:0 auto;
}
body {
background-color: <isprint value="${dw.system.Site.current.preferences.custom.MagicBackground}" encoding="htmlcontent"/>;
}
.jokeContainer {
color:#fff;
}
.jokeContainer .emoji {
font-size: 50px;
margin-bottom: 2px;
}
.jokeContainer .joke {
font-size:20px;
}
</style>
</head>
<body>
<div class="mainDiv">
<div style="width:100%;height:0;padding-bottom:92%;position:relative;"><iframe src="https://giphy.com/embed/12NUbkX6p4xOO4" width="100%" height="100%" style="position:absolute" frameBorder="0" class="giphy-embed" allowFullScreen></iframe></div><p><a href="https://giphy.com/gifs/shia-labeouf-12NUbkX6p4xOO4">via GIPHY</a></p>
<div class="jokeContainer">
<p class="emoji">🤓</p>
<p class="joke">${pdict.joke}</p>
</div>
</div>
</body>
</html>
So what's changed from yesterday?
Lines 16–25: Adds 3 new CSS classes to be used for the dad joke display.
Lines 31–34: Adds the container and content of the joke. Notice the use of pdict
at line 33 - it is the equivalent to the properties
object we set on the render method above. That object had a joke
key and, as such, so does pdict
.
Go Wild 🌈
So now we have all the pieces in place let’s see how it renders:
ROTFL 🤣🤣🤣🤣
Every time you refresh the page, a call will be made to the dad joke service, grabbing a fresh (and hilarious) joke. That joke will then be stored in an object we pass to the render function, which is then used by the ISML template (via the pdict
object) to render the joke!
With this, we can wrap up the Services framework for today. Tomorrow we will continue to tinker with Services framework and see how we can make it more dynamic.
As always, looking forward to your comments either here or on Twitter 😎