Software

The World's Quickest API

Sometimes you just need a quick API. Am I right?

I was working on a project recently and needed just that. I needed an API, and I didn’t want to spend a lot of time on it.

One of my strategies for doing this in days of old was to write up some code-first C# entities, reverse engineer the code to create an Entity Framework model, and serve it using OData. It was great and all that stuff is still around… still supported… still getting improved and released, so you could go that way, but that’s not how I made my last “instant API”.

My last one was even easier.

I found a node package called json-server that takes a JSON file and turns it into an API. Done. Period. End of story. A few minutes composing a JSON file if you don’t have one already and then a few lines of code to turn it into an API.

I also often use a node package called localtunnel that opens a local port up to the internet. Now I spend a few minutes writing a JSON file and 20 seconds opening a port and I have myself an API that I can share with the world.

For example. Let’s say I want to write an app for dog walkers.

Here’s some dog data…

{
"dogs": [
{
"id": 1,
"name": "Rover",
"size": "large",
"gender": "male",
"preferences": [
"feed": true,
"time": "morning"
],
"notes":"Rover doesn't get along well with other dogs"
},
{
"id": 2,
"name": "Spot",
"size": "small",
"gender": "male",
"preferences": [
"feed": false,
"time": "afternoon"
],
"notes":"Spot loves frisbee!"
},
{
"id": 3,
"name": "Jill",
"size": "medium",
"gender": "female",
"preferences": [
"feed": false,
"time": "morning"
],
"notes":""
},
]
}

Now let’s turn that into an API stat! I’m going to be thorough with my instructions in case you are new to things like this.

I’ll assume you have Node.js installed.

Create yourself a new folder, navigate to it, and run npm init -y. That creates you a package.json file. Then run touch index.js to create a file to start writing code in.

Now install json-server by running npm i json-server

The i is short for install. As of npm version 5, the --save argument is not necessary to add this new dependency to the package.json file. That happens by default.

Finally, launch that project in your IDE of choice. Mine is VS Code, so I would launch this new project by running code .

Edit the index.js file and add the following code…

const jsonServer = require('json-server')
const server = jsonServer.create()
server.use(jsonServer.defaults())
server.use(jsonServer.router("data.json"))
server.listen(1337, () => {
console.log('JSON Server is running on port 1337')
})

Let me describe what’s going on in those few lines of code.

The first line brings in our json-server package.

The second line creates a new server much like you would do if you were using Express.

Lines 3 and 4 inject some middleware, and the rest spins up the server on port 1337.

Note that line 4 points to data.json. This is where your data goes. You can make this simpler by simply specifying a JavaScript object there like this…

server.use(jsonServer.router({dogs: {name"Rover"}}))

But I discovered that if you use this method, then the data is simply kept in memory and changes are not persisted to a file. If you specify a JSON file, then that file is actually updated with changes and persisted for subsequent runs of the process.

So that’s pretty much all there is to it. You run that using node . and you get a note that the API is running on 1337. Then you can use CURL or Postman or simply your browser to start requesting data with REST calls.

Use http://localhost:1337/dogs to get a list of all dogs.

Use http://localhost:1337/dogs/1 to fetch just the first dog.

Or to create a new dog, use CURL with something like curl localhost:1337/dogs -X POST -d '{ "id":4, "name":"Bob", ...}

Now you have a new API running on localhost, but what if you want to tell the world about it. Or what if you are working on a project with a few developer friends and you want them to have access. You could push your project to the cloud and then point them there, but even easier is to just point them to your machine using a tunneler like ngrok or Local Tunnel. I usually use the latter just because it’s free and easy.

To install Local Tunnel, run npm i -g localtunnel.

To open up port 1337 to the world use lt -p 1337 -s dogsapi and then point your developer friend that’s working on the UI to fetch dogs using http://dogsapi.localtunnel.me/dogs.

Be kind though. You set your API up in about 4 minutes and your UI dev probably hasn’t gotten XCode running yet. :)

Highlighting the Beauty of Rx

Some time ago, myself and a small team of guys dedicated one evening a week to working on an app.

After the formulation of a ton of good ideas and some real progress on the project, we came to the unfortunate realization that we just didn’t have the after-hours bandwidth the project required.

I still wish I did though, because it’s a good idea, and the idea is often the hardest part of any project.

I don’t want to dive into the details of the project, but I do want to share the pattern we were pursuing - the observable pattern.

The first time I saw Reactive Extensions (Rx) I had a jaw drop experience. Its elegance was apparent despite its implementation being a bit complex. It’s one kind of complex at first and continues to be another kind of complex the more you use it. Since then I’ve been looking for excuses to use this pattern and this library and have found a few, and our app was one of them.

The app I’m alluding to is a game, and it handles a bunch of game data that happens to represent real life players with a mobile device and a GPS, but it could just as well represent 2D or 3D sprites or something besides a game at all.

Without the low-level context, I need you to understand what was going on in the app and that shouldn’t be too difficult.

Imagine every possible event that might occur in a game - everything. A player might move - even a small distance. A player might join… or quit… or shoot… or whatever. These are considered GameEvents.

Now imagine all of these events in one giant stream. That’s right one flat structure. Sort of like a Redux store or a transaction log.

Now imagine all of these events funneling through a single observable inside the game service (the service all players are sending their game events to).

And that should give you enough context to understand what I’ll share next - an observable-based engine for processing game rules.

Now before I embark, know that one of the biggest advantages here is that this general pattern gives us the flexibility to define whatever sorts of rules we want. So one set of rules would implement one game, and another set of rules would implement something altogether different.

Let’s say we want to write a rule that is only interested in when a player has physically moved (as it turns out, that’s one of the most interesting events in the game). In the Rx world, that would look something like…

var playerMoves$ = game.Events
.Where(ev => ev.Type == GameEventType.PlayerLocation);

Note that I’m writing C# code here because that’s what we started with, but this should look pretty similar to some other popular languages you might be using.

What that code says is that I want to declare a new observable (playerMoves$) that is a filtered set of the entire set of game events - only the ones of type PlayerLocation.

Since the player location changes are such an important event, it’s good to set that one up to feed the others. Now let’s get on to another…

//any player collides with any other player
var playerCollisions$ = playerMoves$
.Select(pl => new { PlayerLocation = pl, CollidingPlayers = pl.Game.Players.Where(other => other != pl.Player && other.Location.Distance(pl.Location) < 5) })
.Where(c => c.CollidingPlayers.Any());

This rule depends on the playerMoves$ we declared and set in the previous block and extends it.

This one projects each player that just moved into a new anonymous object that includes any other players that are very close to him (in this game proximity determines a “collision”).

Then we chain the .Where function on there to say that we’re only interested in occurrences where there was a collision (that’s the .Any part).

If you don’t understand that code, spend some time with it. Print it and take it to dinner with you. Put it on your nightstand. This is the sort of code block that looks bizarre first and elegant eventually.

Okay, now I’m only going to take you one step further, and I’m going to do so because although I’ve been calling these “rules,” you haven’t seen a real rule yet.

These were conveniences. These were the application of a couple of Rx operators that essentially gave us some alternate views into that massive stream of game events.

The playerMoves$ gave us a subset and the playerCollisions$ gave us another subset. To create a real rule, we need to take some action. Watch this…

playerCollisions$
.Select(c => new {
c.PlayerLocation,
CollidingPlayers = c.CollidingPlayers
.Where(cp => cp.Team() != c.PlayerLocation.Player.Team()) //make sure it's a collision with an _opponent_
.Where(cp => c.PlayerLocation.Location.Intersects(cp.Team().Zones.Single(z => z.Name.StartsWith("Zone")).Definition)) //in opponent's territory
})
.Subscribe(c => {
//send the player to jail
c.PlayerLocation.Player.NavigationTarget =
c.CollidingPlayers.First().Team().Waypoints.Single(w => w.Name == "Jail");
});

So this block starts with that convenience observable - playerCollisions$.

Then it projects it to an anonymous object that includes the player(s) that are in collision. In that filter, the colliding players are filtered to only the players that are a) on the other team and b) in the other player’s area (zone). This rule actually comes from Capture the Flag in case you didn’t recognize it and occurs when a player gets tag running in another player’s territory.

And then what may be considered the interesting part if I weren’t such a geek and found all this stuff to be interesting :)

The .Subscribe method. This method determines what happens when this sort of collision occurs. In the case of Capture the Flag, the player is to be sent to jail - the other player’s jail that is. Thus…

c.PlayerLocation.Player.NavigationTarget =
c.CollidingPlayers.First().Team().Waypoints.Single(w => w.Name == "Jail");

That is… set the player’s (the one that got tagged) navigation target (where the app tells the player to go) to the other teams waypoint labelled “Jail”.

And that’s as far as I’ll go.

Remember, the purpose here is to help you understand why you might choose to use the observable program in your application and to show you how terse and elegant it can make your code.

Happy hacking!