Teach Your API Test Platform to Send Callbacks

I already wrote about using Prism as an API test platform but I didn't include an example with callbacks so this post is to fill that gap! If you didn't read the previous post, the tl;dr is that Prism is a nodejs open source tool that can take your OpenAPI specification and then do an impression of your live API, validating the API calls sent to it and responding with the example data described in the spec. It can also follow up the API response and send an HTTP request of its own to mock the callbacks described in your OpenAPI spec.

Describing Callbacks in OpenAPI

I'm working with the Nexmo APIs quite a bit so here's an easy example from one of their specs. It's from the "Number Insight" API - you provide a phone number and the API returns you information about that number. There's a few different levels of information (and different levels of cost for each), but the "Advanced" level is pretty unreliable if you call it synchronously - so instead Nexmo will respond to your API call, then send a followup request to the URL you specify with a payload of all the data in it.

Here's how the OpenAPI spec looks:

  "/advanced/async/{format}":
    parameters:
      - $ref: "#/components/parameters/format"
    get:
      operationId: getNumberInsightAsync
      summary: Advanced Number Insight (async)
      parameters:
        - $ref: "#/components/parameters/callback"
        - $ref: "#/components/parameters/number"
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/niResponseAsync"
      callbacks:
        onData:
          "{$request.query.callback}":
            post:
              operationId: asyncCallback
              summary: Asynchronous response
              description: Contains the response to your Number Insight Advanced API request.
              requestBody:
                content:
                  application/json:
                    schema:
                      $ref: "#/components/schemas/niResponseJsonAdvanced"
              responses:
                "200":
                  description: OK

(if you want to see the whole thing, it's on GitHub )

The callbacks section details the incoming requests to expect as a followup to the client's API call, and what response to send. In the initial request, the callback parameter specifies where the callback will be directed to - and Prism can do that too.

Mocking The API and Callbacks

I can start up the "pretend" API with Prism like this:

prism mock number-insight.yml

Prism will output the endpoints that it got from the spec and then report its location - for me that is usually http://localhost:4010.

In order to receive the callback, I'll need to pass a URL that Prism can reach. This is one scenario where you won't need a public URL to test a webhook - because the webhook is coming from another local tool. In this case, I've got a simple webserver running on port 8080 that will simply output the data it receives so I can inspect it.

Ready? Here's my curl command to request the async endpoint from the local mock API, and gives the callback to send the data payload to:

curl "http://localhost:4010/advanced/async/json?api_key=123&api_secret=456&number=44777000777&callback=http://localhost:8080"

I get a response to my API call, containing a request_id and some other information, then (but seemingly instantly) Prism follows up by sending more example data to the callback URL I specified before.

Testing API Callbacks Locally

This setup is brilliant for a situation like this where I want to develop something to handle this callback - but I don't want to keep on hitting the live API (not to mention that I will run out of credit if I keep hitting this one!). I can work locally, regardless of whether my connectivity is great or even whether the API is up (or even exists yet).

In the future, Prism is expected (by me at least) to also have support for the new Webhooks feature that is slated for OpenAPI 3.1 - enabling us to use a local mock server to send incoming requests as well as handling our outgoing ones. I, for one, can't wait!

Using Config Files with Ngrok

I'm a huge fan of Ngrok, a tool to create a secure tunnel to your laptop. It is brilliant for testing, well, anything running locally really. Someone asked me about my setup recently and I'm using a couple of config files to keep things quick and consistent, so I thought I'd share here what I shared with them.

You can use a central config file for ngrok, and/or specific config files for each project. I use both, so I'll show you around my setup. Continue reading

Relative Links with IBM Cloud API Gateway

I work quite a bit with serverless tech, particularly on IBM Cloud since I work there. At the moment I'm building a microservice using web actions. When a user creates data with a POST request, I want to redirect them to the URL of the new thing they created - but for that I need to know the URL that it was accessed with. This is a relatively new feature on API Gateway so here's a quick howto for grabbing that URL in both JavaScript and PHP. Continue reading

Testing API calls in PHP with Guzzle Mocks

I'm working on a CouchDB library for PHP, and so I needed to write some tests for it. CouchDB has an HTTP API so I'm basically making web requests and while I could certainly set up a test database and run full-on integration tests, there are a few limitations with that approach. Firstly: it means I'm testing the database as well, which isn't what I want and brings extra dependencies that make the tests harder to run. Also: I want to be able to test error cases, rate limiting and so on, that would be difficult to recreate reliably. Continue reading

Recover Bitly Bundle Data

For some years I've been creating a bundle of links covering articles I recommend for various topics in the Zend Certified Engineer Exam (if you can here looking for the bundle itself, it's at http://lornajane.net/zce-links-collection). This was done using bitly's bundles feature, which I thought was a great way to share links. In fact I had 10-15 bundles that I had created from collating all the links in a particular training course or talk, so that people didn't have to try to write down URLs as I went along. Unfortunately they sunset their bundles and then removed them completely, and I missed the announcement (it all happened quite quickly, they'd seen some abuse of the feature, it's free, all totally reasonable) BUT they also didn't respond to my support questions about how to recover the data.

It turns out, it's an undocumented feature on their API, so here is everything I know about recovering your bundle data, including the script I used to rescue my own data. Continue reading

What Does URI Stand For?

I get a lot of complaints about an API that I maintain (http://api.joind.in) which is "missing" the ID field. This ID field is the database's primary key; if the user doesn't have access to the database (they don't), then it seems to me that the primary key probably isn't all that useful.

Instead, the API publishes each record with a unique uri field. If this record is referred to by another record, then this full identifier will be used in every case. If this record should be included in a collection, this exact same identifier will be used there, too. You can reach the resource directly by requesting its URI. In the same way that we might refer to a website by its URL, we refer to records in RESTful systems by their URI*. If you need to store these somewhere for your own use, you can use whatever key you like with the local storage, you may even choose to use the uri field as it is unique.

* URI stands for Unique Resource Identifier

Doing Google Custom Search via API

I'm working on a project that uses a search engine to show images on a particular topic ... but I need my search to be localised since I'm in the UK and so "football" doesn't mean what a generic search engine thinks it means. Getting this working was MUCH harder than I expected, so here's a quick post on what I did so that I can remember for next time - and if this helps you as well, then great :)

Google Custom Search Engine

It's possible to set up and configure a custom search engine in Google, so you can configure some settings and the search will always use those settings. To begin, go to http://www.google.com/cse. Here you can create a search engine, give it a name and description, and then set some options. You can choose whether to search for images, or not, or images only. You can include or exclude certain sites, or search everywhere and just prefer certain sites. Continue reading

Joind.in at the PHPNW Hackathon

It's that time of year again, the PHP North West conference is almost upon us, and this year they are once again running a hackathon. These events are a great way either to carve out some time to get your head down and hack on an idea that's been in the back of your mind for a while, but they're also a fabulous way to get involved in collaborating on projects. At PHPNW, you'll find there are quite a lot of open source projects at the hackathon, standing by to take on anyone interested in getting involved, either just for the evening or beyond. I'll be there, representing joind.in, a tool which is used by the conference itself. So what kinds of things will there be to do and how can you get involved? Continue reading

Twitter Search API Using PHP and Guzzle

In case you missed it, Twitter updated their APIs recently, so that you have to authenticate to use even their search APIs to return publicly-available results. This is an increasing trend for API providers, to provide either very limited or nonexistent access for unauthenticated users, I think so they can rate limit consumers that swamp them. To cut a long story short, that meant I needed to update my dashboards that keep an eye on twitter searches to do more than just call file_get_contents in the general direction of the right URL. Continue reading