Showing posts with label integration. Show all posts
Showing posts with label integration. Show all posts

Wednesday, August 12, 2015

Mocking HTTP Servers

I am doing some HTTP-based integration work for a client on a GWT-based project (which is why I wanted to know which HttpClient version to use). I'm still waiting on access to the third-party system, but I've already written and tested the code to generate the XML request and parse the XML response, so I wanted to take a step farther and write the code that would connect that with HTTP:

  • Generate XML using the XML writer/generator
  • Send the XML over HTTP
  • Wait for the HTTP Response, check it (status code, etc)
  • Parse the HTTP response's body using the XML parser/reader

But if I were going to do that, I want to test it, and testing it requires something to listen for HTTP requests (or to mock out the HTTP client, but this is already a pretty thin layer). I don't have access to the real service yet, so I can't write an integration test and, to be honest, I tend to try not to rely on integration tests. So basically I want something that can pretend to be an HTTP Server of some kind but that has an API that makes writing test code convenient. I went looking for candidates to easily test an HTTP-based client in Java.

When I'm picking tools in other platforms, I often consider the popularity of the dependency as well as other signs of its maturity. In Java, it's hard to get good numbers for such things. First of all, while there are some dependency management systems for Java, they're not universal or nearly-universal like they are on other platforms. Maven's central repository is probably the closest thing to that, but even then, there are lots of projects that download their dependencies directly. And, sadly, Maven doesn't publish stats about their dependencies, stats you could use to gauge how many other people are using and trusting a particular library vs. another.

However, after looking at some of the alternatives, I decided to start with mocky.io. That worked pretty well, but I don't really love using an external server for a simple test. That test wouldn't run offline, wouldn't run if the internet was down, or if mocky.io was having problems. It's basically too much of an integration test, and not even an integration test against the real service. Still, it worked well, and it's a reasonable place to start if you just want to fire up a simple test without adding new dependencies to your project.

I looked at alternatives to replace it. WireMock has a reputation for being very capable and having a good API, but perhaps not kept as up-to-date as one might like and a little heavy-weight. I also looked at MockServer, which looks very capable but also looks pretty heavy. My requirements for now are super-simple, so I ended up using okhttp's MockWebServer, one of Square's open-source projects. It's very simple, reasonably light, very fast, and has enough capability for my simple needs. I like it.

There are lots of alternatives, from something custom (Netty, RxNetty, Spray) to other competitive libraries (jailer,mock-http-server) and services (Sandbox), but for the moment, MockWebServer does the job for me.

Sunday, August 12, 2012

Err Chatbot

Although Hubot is fun, and is already in use for gluing development chatrooms to infrastructure of all sorts at companies like GitHub, there are alternatives. I've had a couple of conversations with Guillaume BINET whose Err chatbot might be the sort of alternative you might consider.

Err (pronounced 'R2') is written in Python, is extensible through plugins which look reasonably easy to write, and has a catalog of pre-existing plugins. If you'd rather use Python than node.js to extend your chatbot, Err might be a good choice for you.

I haven't tried it yet -- there are two blocking issues for me:

  • XMPP-only: I currently use CampFire, because I like the available clients and the native support for history/searching.
  • No Web Hooks / Notifications: Err is mostly built for responding to user requests in the chatroom. I often use Hubot to respond to external services, like an SVN checkin or CI build notification. You could presumably write this into Err yourself, but it doesn't make that easy for you yet.

These may come soon so if you're interested in Err, you could star or watch the project on GitHub and keep an eye on it.

Thursday, June 16, 2011

Will iCloud Allow Data Sharing 'between' Applications

Will any two applications be allowed to share data on iCloud, or will they be restricted to applications that are, by some definition, the "same application"?

One of Apple's primary examples for iCloud data sharing was the iWork suite, where a single Pages document could be accessed on the Mac, iPhone and iPad all through iCloud. Are all of these the 'same application'?

Application Identity
What does it mean to be the 'same application'?

In iOS the simplest answer would be the "app id" that all applications sold through the iOS app store are required to register. If you write a universal application for iOS that can be run on the iPad and iPhone, these would have the same app id, but if you sell two distinct applications, one for iPad and one for iPhone, these will have different app ids.

Interestingly, the Mac app store also requires app ids. If you sell an application with the same name and roughly the same functions through the Mac app store and iOS app stores, do you give them the same app ids?

iCloud Data Sharing Restricted by App Id
If iCloud were restricted so that you could share data through multiple applications with the same app id, this would presumably encourage developers to build universal applications rather than distinct iPhone and iPad versions if there were any value in data sharing.

For instance, if Plants vs. Zombies could only share game state data if it were a universal app, then I'd strongly prefer PopCap to start selling universal applications, even if that meant the cost of their iPhone version were to rise accordingly.

Similarly, I have OmniFocus for Mac, iPhone and iOS; these are distinct applications -- will they be allowed to share data through iCloud?

Unrestricted iCloud Data Sharing
If iCloud data sharing were allowed between any two applications who were to agree on some details (namespace, format, etc.), this could enable new kinds of application integration, which would be interesting in its own right, as well as allowing iPad and iPhone versions of the same application to share data without becoming universal apps.

I'm not trying to present a false dichotomy here -- there are probably other options, but I don't know what they are, and i'm not going to try and guess. I'm interested to see how iOS and Mac apps are allowed to share data using iCloud and what the impact of that sharing will have on universal apps and application integration.

Thursday, April 28, 2011

Integrating Applications in iOS and X-Callback-URL

When you’re using an iOS app, it fills the screen and becomes the whole experience of using the device. You’re not using the iPhone or the iPad, you’re using Twitter, Reeder or Instapaper. John Gruber has used the phrase 'app console' to aptly describe the way this feels.

It’s a very immersive experience, which works well when a single application lets you accomplish an entire task from start to end, but it breaks down somewhat when you need to use multiple applications to accomplish a single task. There’s no overlapping windows, no multi-display systems and even real multitasking is a recent addition. While you can certainly switch between applications and use copy-and-paste to share some data, getting applications to work together in iOS isn’t always a piece of cake.

Imagine writing a typical blog post: you need to browse a few web sites, link to them, upload an image and embed it, write the copy and push that up somewhere. An iOS application that allows you to post pictures and text to your blog using blogging APIs and has an embedded web browser could go a long way to making that fairly painless. But try and do that using separate tools, and you’ll need to switch tabs in Safari, cut-and-paste the URLs into an editor, upload an image to flickr, copy its link and switch back to the editor, then transfer the whole thing up to your blog. When each application switch is a double-tap, swipe, tap and when copy-and-paste is a somewhat time-consuming affair, you can imagine that you quickly reach the point where you decide to hold off until you’re back at your laptop.

As a result, many of the best iOS application experiences are applications that help you do all the things you need to do to accomplish a task. Rather than having a text editor, a web browser and an FTP client, you use a blogging client. These all-in-one applications are not unique to iOS but they’re more important in iOS than they would be in a desktop environment, where using a collection of tools or a single tool is a tradeoff that each person might make differently.

Integrating iOS Applications

Even before multi-tasking, but particularly after iOS 4.0 brought multi-tasking to iOS devices, iOS apps have increasingly been integrating with each other. Reeder allows me to send links to Instapaper, Twitter, bookmark them on delicious and open links an embedded web view. Instapaper lets you look up word definitions using Terminology.

When you want to integrate iOS applications, there are a few ways to go about it, including: integrate with a server (e.g. Instapaper, DropBox), custom urls with protocol handlers, and documents.

Integrating through Servers

Applications running on iOS can communicate with servers, and in so doing, indirectly interact with one another. For instance, when I use Reeder to save a link to Instapaper, it does so by telling Instapaper’s servers, using an API, that I’d like to save a new link to my Instapaper account. When I then load up Instapaper, it downloads updates from the server, including new documents that I’ve saved from Reeder.


In this case, neither iOS application is explicitly aware of the other one, but they both integrate with the same server, leading to a sort of indirect integration. This works fairly well for queue-style interactions, where you’re not expecting necessarily to switch back and forth between the applications, but rather dispatch some information that you’ll look at in the other application later.

Integrating through a server can be fairly simple, but it has lots of hidden complexities if you want your integration to be robust. If the iOS device is offline, or can’t reach the server, you may need to build a queueing mechanism to store data locally and send it up to the server once your connection to the server is available again.

Dropbox

Dropbox is a special case of server-based integration. It’s not fundamentally different from a technology perspective than integrating with any other server, but it is an increasingly common integration point across multiple platforms and has been expanding strongly in iOS applications. Dropbox provides a mobile API and makes integration through dropbox as easy as it can be. As a result, many apps for iOS have built-in Dropbox support, acting as a sort of shared filesystem, albeit a remote filesystem.

For instance, you could save a file from the Atomic web browser to Dropbox, then edit that file using something like Elements:



Again, neither Atomic nor Elements knows about the other, and the apps themselves don’t integrate at all, but they do both work with a common server: Dropbox.

Documents

Unlike most desktop operating systems, user applications in iOS do not share areas of the filesystem with other applications. Users can’t save a file to a location that’s accessible to both applications and then switch applications and load the file. It is possible, however, for each application to register the kinds of files they’re capable of handling, and to ask iOS to open a file on your behalf. UIDocumentInteractionController will then offer the user a choice of applications known to handle files of that type, resulting in another application being asked to open that file.

For instance, if you open a PDF in Dropbox and click the ‘Action’ icon, iOS will give you the option of opening the file in one or more of the applications that support PDFs. On my phone, that’s iBooks and Evernote:
Opening a File in Another Application


Strictly speaking, the Dropbox and iBooks applications aren’t integrated. They know nothing about one another, and the Dropbox app cannot explicitly invoke iBooks. However, because iOS knows about both applications, it provides a mechanism that allows them to feel as if they’re integrated. Even in this scenario, iOS doesn’t actually share a file between applications. If you open a file in another application, iOS makes a copy of that file in the Inbox folder of the destination app. Each app retains its own copy of the file and decides what to do with it.

This form of interaction is useful for transferring a file from one application to another, but it’s an awkward approach for most other kinds of integration between applications in iOS.

Protocol Handlers and Custom URL Schemes

In addition to files, iOS allows applications to indicate that it is able to open URLs of particular schemes, and to ask iOS to open URLs on your behalf. This turns out to be a handy way to integrate two applications that don’t need to pass files around. This is the most commonly-used1 way to integrate two iOS applications that don’t integrate with a common server.

For instance, if I open Reeder and decide that I want to share an article I’m reading on Twitter, I can press the action button, select ‘Twitter’, compose a tweet in Reeder, and then it will send the contents of that tweet to the Twitter application using a custom URL scheme (twitter://post?message=Message%20Text):

Sending to Twitter from Reeder

Once again, Reeder doesn’t explicitly know that I have the Twitter application installed. All it knows (if it cares to check) is that iOS can open a URL with the “twitter:” scheme. There’s nothing that prevents another application from registering the same scheme, although unfortunately, iOS does not have a mechanism for selecting one of several applications that can handle the same URL scheme2.

This works reasonably well, but it’s a one-way ticket. If you want to return to Reeder after posting a Tweet, you’ll have to do it yourself (from the home screen or the recent-application tray). This isn’t terribly hard, and iOS users are used to it, but it’s not a seamless experience.

Where it gets worse is if you want some kind of two-way integration. What if you want to do a thesaurus lookup where another application can offer you alternative words? With a one-way integration, you’re left to copy the word from the destination app, return to the source app and then replace the original word using a paste. It’s plausible, but very clumsy, and require a lot of tapping and holding.

X-Callback-URL

The x-callback-url spec proposes a means of allowing a more seamless two-way integration, still using custom URL schemes. Essentially, applications using x-callback-url structure their custom urls in a particular way so that the called application knows the name of the calling application and how to indicate success and failure to the calling application, potentially carrying additional ‘return’ data.

The thesaurus lookup example is pulled directly from Terminology, the first iOS application to offer support for x-callback-url. If your application supports x-callback-url, you can request a replacement word from Terminology, tell it the word you’d like to replace, and let it know which URLs to invoke in your application the case of success and failure. iOS will switch to terminology, let you choose a replacement word, then if you touch the return button, Terminology will ask iOS to open the success url, causing your application to launch, and giving you enough information to replace the original word:



The Terminology API documentation has example interactions and even a short video allowing you to see x-callback-url in action. Instapaper now supports x-callback-url for adding pages to your Instapaper account. This gives you offline queuing for free, although it does require a round-trip to the instapaper application.

X-callback-url offers the potential for iOS application integration to be bi-directional, reducing the friction that makes using multiple applications to get a job done somewhat painful.

Small Pieces, Loosely Joined


Although the sweet spot for iOS applications will likely remain all-in-one applications, I’m happy to see movement towards applications that can work together in a more seamless manner, bringing us closer where iOS software can form an ecosystem of related and connected apps, not a market of isolated all-in-one apps. I’m looking forward to the future where iOS apps form a loosely connected network where getting a job done with three applications doesn’t feel like juggling.

Footnotes and References

  1. This is so common that there is an index of viable integration url schemes at HandleOpenURL.
  2. The documentation says, “Note: If more than one third-party application registers to handle the same URL scheme, there is currently no process for determining which application will be given that scheme.”