Advertisement

Automating Tasks With Services

by

This Cyber Monday Tuts+ courses will be reduced to just $3 (usually $15). Don't miss out.

If you’ve used a Mac for any length of time, you’ve no doubt encountered the services menu at some point, and you’ve probably wondered to yourself "just what is that menu for?" Well, in this tutorial, we’re going to decipher the mystery of the services menu, and we’ll see just how useful services can be by creating one of our very own that we’ll be able to use whenever we need to replace a long, ungainly URL with a shortened one.


What Is a Service?

In short, services allow the apps on your computer to share functionality amongst themselves. For example, the standard Mail app provides your other apps with the ability to create new email messages or notes based on text you currently have selected.

New Email With Selection
The "New Email With Selection" service provided by Mail.app

The beauty of services is that they allow apps to focus on what they do best by removing the burden of providing loosely related features that other apps already provide.

In addition to allowing your apps to share functionality with one another, you can also create your own services. If you’re a command line junky, then you understand the power that services provide, since they essentially allow you a means for creating context-aware scripts for your windowed apps. We’ll see an example of this by writing a service of our own. The service we’ll be writing in this tutorial will allow you to select a URL in any application that allows text editing, and convert it into a shortened URL through the use of bit.ly's URL shortening service without ever leaving the app you’re currently in or touching a browser window.


1. Get a bit.ly API Key

Before we can get started with our service, we need to do a little setup. In order to use bit.ly to shorten a selected URL, we’ll need to have developer access to the service. So, our very first task will be to sign up for a bit.ly developer account and get our API key.

To do that, you’ll need to navigate to the API Key webpage, and, if you already have a developer account, just sign in.

bit.ly API key request page
The bit.ly developer account API key request page

Otherwise, you’ll need to sign up for new account.

bit.ly developer account sign up
The bit.ly developer account sign up page

Once you’ve finished either signing in or signing up, you’ll be taken to a page that will give you your API key.

bit.ly developer API key
The bit.ly developer account API key page

Once you’ve got your developer account setup and you’ve retrieved your API key, you’ll be good to go, but you still need to look over the API docs to get an idea of how to use the bit.ly service programmatically. Specifically, take a look at the documentation for the shorten method as that’s the one that we’ll be using in our service.


2. Create the Service Workflow

Step 1

So, now that we have our API key, we’re ready to create our new service. We’ll be using Automator to create our service, so go ahead and open it up now and select Service for our new workflow’s type.

Creating a new Service workflow in Automator
Creating a new Service workflow in Automator

Step 2

Check the Output replaces selected text checkbox in the section atop the workflow area. This will ensure that the selected URL in our app is replaced with the shortened version emitted by our service.

Check the Output replaces selected text option
Check the Output replaces selected text option

Step 3

Now that you have your new workflow setup properly, you can go ahead and add your first action to it. Do a search for the Run Shell Script action and drag and drop it into the workflow area.

Adding a new "Run Shell Script" action to the workflow
Adding a new "Run Shell Script" action to the workflow

Step 4

We’ll be using Python to write the script that will send the long URL to bit.ly. By default a new service uses your default shell as its scripting language, so you’ll need to change it by selecting /usr/bin/python in the Shell dropdown list.

Selecting Python as the scripting language for the "Run Shell Script" action
Selecting Python as the scripting language for the "Run Shell Script" action

Depending on your preference, you may find it easier to deal with the input as if it were passed into your script as a command line argument rather than read it in from standard input. To do so, you’ll need to select the as arguments option from the Pass input dropdown.

Choosing to have the input passed into our "Run Shell Script" action as arguments
Choosing to have the input passed into our "Run Shell Script" action as arguments

Once you have everything setup according to the instructions above, your Automator workflow should like just the following:

The final state of all of the settings for the service
The final state of all of the settings for the service

3. Add the Code

The code for this service is relatively simple. Essentially, all we are doing is constructing a URL with our username, API key, and long URL, making a request to that URL, and returning the shortened URL in the response. If you have any experience with programming, you should have no problem following the steps listed below. If you’re not an experienced programmer, but interested in learning a bit, then the following explanations should be of interest. If, however, you simply want to create the service and not be bothered with the details, you can skip ahead to The Full Source Code section below and simply copy and paste the code into the Run Shell Script action in your service.

Step 1

We’ll first need to import the urllib and urllib2 modules. They’ll be used to properly encode the data that we’re sending to the bit.ly service and to send the actual request itself. We’ll also need to import the json package to turn the response we get back into a python dict. Finally, we’ll need to import the sys package to give us access to the command line arguments. This last module is necessary since we chose to pass input as arguments when we first added the Run Shell Script action.

import urllib2
import urllib
import json
import sys

Step 2

In this step we’ll create the payload (i.e., the data) that we need to request the shortened URL. To begin, we’ll add two constants to hold our bit.ly developer account username and API key that we generated in the first portion of this tutorial. Then, we’ll create the payload (i.e., the data) for the request. To do that, we create a simple dict with three key/value pairs. The first two will be our username and API key and the third will be the URL that we wish to shorten, which we’ll retrieve from the list of command line arguments.

USERNAME = 'you_username'
API_KEY ='your_api_key'

payload = {
    'login': USERNAME,
    'apiKey': API_KEY,
    'longUrl': sys.argv[1]
}

Step 3

Once, we have our payload, we’ll need construct the URL for the request. We’ll first need to URL encode our payload data since it will be going into the querystring of the request, and then concatenate it onto the endpoint (i.e., URL) for the bit.ly shorten method.

querystring = urllib.urlencode(data)
url ='https://api-ssl.bitly.com/v3/shorten?%s'% querystring

Step 4

Now that we have the full URL, we’re ready to request the shortened version. We first create a Request object with the URL we created in the previous steps. Then, we make the request and retrieve the data from the service. The data will be sent back as JSON, so we’ll need to translate that into a python dict using the json module.

request = urllib2.Request(url)
response = urllib2.urlopen(request)
message = json.loads(response.read())

Step 5

Once the data has been retrieved and parsed into a python dict, the only step left is to extract the shortened URL from the dict and return that. To return the URL, we simply print it.

print message['data']['url']

The Full Source Code

The full source code for the service is listed below, so you can simply copy and paste it into the Run Shell Script action in your Automator workflow.

import urllib
import urllib2
import json
import sys

USERNAME = 'your_username'
API_KEY ='your_api_key'

data = {
    'login': USERNAME,
    'apiKey': API_KEY,
    'longUrl': sys.argv[1]
}

querystring = urllib.urlencode(data)
url ='https://api-ssl.bitly.com/v3/shorten?%s'% querystring
request = urllib2.Request(url)
response = urllib2.urlopen(request)
message = json.loads(response.read())

print message['data']['url']

4. Test the Service

To test our service we’ll need to add another action right before the Run Shell Script action. This new action will simply feed a static URL into the Run Shell Script action allowing us to verify that the script works correctly. Let's add that new action now.

Step 1

Do a quick search for the Get Specified Text action and add it to your workflow right above the Run Shell Script action.

Add a new "Get Specified Text" action for testing the service
Add a new "Get Specified Text" action for testing the service

Step 2

Once you have the new action added, pick a nice long URL and add copy and paste it into the new action’s text box.

Add a long test URL to the "Get Specified Text" action to test the "Run Shell Script" action
Add a long test URL to the "Get Specified Text" action to test the "Run Shell Script" action

Step 3

Now your ready to test your service. Click on the Run button in top right corner of the Automator app’s toolbar.

Run the service with the test URL
Run the service with the test URL

Step 4

You’ll know the test is complete by checking the output in the Log section of Automator at the bottom, right-hand side of the app. In the log section, you should see a handful of green checkmarks beside tasks that happened during the run. The last of the tasks should hopefully say Workflow completed. If it does, the test completed without failing.

Check the log to see when the service has finished executing
Check the log to see when the service has finished executing

Step 5

Now that the test has finished running, you can check its output to make sure that it worked the way you expected it to. To do that, click the Results button at the bottom, left-hand side of the Run Shell Script action. This will reveal a new section that contains the output of the action. If you see a nicely shortened bit.ly URL there, you know the service is working properly.

Check the result of the test to make sure the "Run Shell Script" action worked correctly and shortened the URL
Check the result of the test to make sure the "Run Shell Script" action worked correctly and shortened the URL

5. Deploy The Service

With your tests completed and your service working properly, you’re now ready to deploy the service. In other words, you’re ready to make it available to all of the apps on your machine. To do that, all you really need to do is save the workflow and give it a name, but before we do that, let’s make sure that the Get Specified Text action that we added to the workflow for testing purposes doesn’t get in the way.

Step 1

As of right now, if we tried to use our service it would return only the shortened URL of the test URL we added in our last section. The reason for that is that our Get Specified Text action is being called before our code, and so it's completely ignoring any input we give it (i.e., the currently selected text) and instead just sending the URL in its text box into the Run Shell Script action. You can simply remove the action if you wish, by clicking on the Get Specified Text action in the workflow and hitting the delete button. But, what if you make changes to code in the future and want to test those changes? Well, you could just add the Get Specified Text action and a test URL again when the time comes, or you could keep the one we currently have and just disable it for the time being. To disable the action, select the action in the workflow and Control-click it to display the context menu, then select Disable.

Disabling the "Get Specified Text" action so the new service will work with selected text
Disabling the "Get Specified Text" action so the new service will work with selected text

Step 2

Once you’ve disabled or deleted the Get Specified Text action, you can save the service—give it the name Shorten selected URL—and start using it in all the other applications on your system. Let’s go ahead and give our new service a try now.

Step 3

To test our new service, we’re going to use the TextEdit application since it comes standard on all Macs. Go ahead and open up TextEdit and add a long URL to it. Then select the URL and select TextEdit > Services > Shorten selected URL. It should take about a second for the request to make it to the bit.ly service and back again, but when it’s finished, you she the selected text replaced with a newly shortened bit.ly URL.

Testing the new service "in the wild" using TextEdit.app
Testing the new service "in the wild" using TextEdit.app

6. Add a Keyboard Shortcut (optional)

The last step in the development in our URL shortening service is an optional one. Basically, shortening a URL is something I do on a very regular basis, and, for me at least, having a keyboard shortcut associated with the service makes it so much easier to use than navigating through the Services menu each time. With than in mind, we’re going to add a keyboard shortcut to our new service.

Step 1

To add a keyboard shortcut for our new service, you'll need to open System Preferences and navigate to the Keyboard pane. Then select the Keyboard Shortcuts tab followed by the Services item in the list on the left, and scroll through the list of services until you find the new service—you should find it within the Text section.

Adding a keyboard shortcut for the new service
Adding a keyboard shortcut for the new service

Step 2

Now we just need to add the actual key combination that we’ll use to invoke our service. To do that, click on the add shortcut button and press the key combination that you prefer. I’ve chosen the combination Control-Option-Command-s for mine, but you can choose anything you like, though you should try to avoid key combinations already in use.


What Next?

In this tutorial we’ve taken an in depth look at services, a very powerful feature of OS X. We’ve learned what services are and how to create them, and, during the course of this tutorial, we’ve created one of our own that we can use to shorten lengthy URLs using bit.ly. The only question left is "what next?"

Do you have any ideas for news services that you’d like to create? Have you created any in the past? Share your ideas and code in the comments below!

Advertisement