How to use Vercel's serverless functions to make an ipify clone

Following Jesus; Husband; Father; Developer; Gamer; Tinkerer; Writing about code
Search for a command to run...

Following Jesus; Husband; Father; Developer; Gamer; Tinkerer; Writing about code
No comments yet. Be the first to comment.
Today ChatGPT lied to me, so I’m setting the record straight. This is my question: “If an endpoint in an OpenAPI spec has multiple tags, what will Swagger Codegen do?”. Because Swagger Codegen organized the generated code into api/tag_name_api files....

A Short Story

Universal Libraries, The Internet, and Generative AI

This is the article I wished existed when I needed to support accounting functions. Double-entry Bookkeeping may seem esoteric and unnecessarily complicated, but actually describes a simple framework for maintaining a correctible and auditable record...

How to Change Databases without Downtime

Vercel (formerly ZEIT now) is a fantastic platform for deploying static websites and serverless functions. Let's dig into what their serverless functions can do by rebuilding ipify in node.js (which if you didn't know is a fantastic and totally free reverse ip address lookup service).
I'm assuming you've gotten an account with Vercel and installed their cli. You will also need npm as we will be using the request-ip package to handle finding the IP out of the HTTP request.
Anywhere on your computer, let's create a folder called ipify-clone for our project:
$ mkdir ipify-clone
$ cd ipify-clone
And let's put the basic folders and files we'll need in there:
$ echo '{}' > package.json
$ echo '{ "version": 2 }' > now.json
$ echo 'ipify clone' > index.html
$ mkdir 'api'
$ touch 'api/json.js'
$ touch 'api/text.js'
$ mkdir 'api/jsonp'
$ touch 'api/jsonp/[callback].js'
And now let's deploy once to confirm everything is working properly:
$ now
After going through any prompts that gives you and allowing it to finish, it should copy the url it deployed to into your pasteboard (it should also be displayed in the command output). Open a browser and visit that link; you should see a page that says ipify clone in the top left corner. Not the most exciting webpage in the world but we have to start somewhere right?
There's three endpoints we're going to build:
{ "ip": "255.255.255.255" }userSuppliedCallback({ "ip": "255.255.255.255" })For all of them, we'll use the request-ip package to actually get the IP address. So, let's install that and start making the first endpoint:
$ npm install request-ip --save
In your favorite text editor, open the JavaScript file we created at ipify-clone/api/text.js. We want to do three things for this endpoint:
200 (OK)Content-Type header to text/plain to tell everyone this is a plaintext responseThe code for that looks like this:
const requestIp = require('request-ip');
module.exports = (req, res) => {
res.setHeader('Content-Type', 'text/plain');
res.status(200).send(requestIp.getClientIp(req));
}
Since this is our first endpoint, let's go into detail for this one.
First, we need to include that package we installed so we can use it, so const requestIp = require('request-ip');.
Then, the way Vercel works is we need to set module.exports to an arrow function, that accepts two objects: the request and the response; (req, res) => { ... }. This will be the same for all of our serverless functions.
Inside the function, our job is to manipulate the response object using the request object to make our api do what we want. .setHeader is how we set the Content-Type header we want; .status is how we set our status; requestIp.getClientIp is how we get the IP address; and .send is how we set the body of our response.
Let's deploy again and see what happens:
$ now
Again taking the url it gives us let's visit <the-deployment-url>/api/text.
If all worked you should see your IP address! Notice how Vercel took our text.js file in the api directory and turned it into an endpoint located at /api/text (and if you inspect the page and look at the request, you should see the headers include text/plain). Vercel does this automatically for any file or folder located in /api.
One down, two endpoints to go!
This is almost exactly the same as the text endpoint; the only differences are:
Content-Type header to application/json instead of text/plainVercel has a nice method off the response object for returning JSON, named (creatively) .json. Otherwise the code to put in the ipify-clone/api/json.js file should look familiar:
const requestIp = require('request-ip');
module.exports = (req, res) => {
res.setHeader('Content-Type', 'application/json');
res.status(200).json({ ip: requestIp.getClientIp(req) });
}
If you deploy again and visit <the-deployment-url>/api/json, you should again see your IP, but this time wrapped in JSON! I know it's a big accomplishment but try to contain your excitement.
(We could have also just built the json return manually)
const requestIp = require('request-ip');
module.exports = (req, res) => {
res.setHeader('Content-Type', 'application/json');
res.status(200).send(`{ "ip": ${requestIp.getClientIp(req)} }`);
}
For this endpoint, we'd like to allow the client to specify what callback to use in the jsonp. There's a lot of ways this could be done, but let's use Vercel's path segments to demonstrate what they can do.
If we name a file in our api directory with square brackets, like [parameter].js, Vercel will allow any request like api/anything or api/somethingelse and call that [parameter].js function with the value as a parameter in the request object.
So, by making a function in ipify-clone/api/jsonp/[callback].js our users will be able to visit /api/jsonp/customCallback and we can include that value of customCallback in our response by accessing req.query.callback.
const requestIp = require('request-ip');
module.exports = (req, res) => {
res.setHeader('Content-Type', 'application/javascript');
res.status(200).send(`${req.query.callback}({"ip": "${requestIp.getClientIp(req)}"})`);
}
Deploy again and visit <the-deployment-url>/api/jsonp/callback and you should get a response like callback({"ip": "255.255.255.255"}). And of course you can visit other paths like <the-deployment-url>/api/jsonp/customCallback or whatever you'd like.
You can deploy this to production using now --prod. If you've purchased a domain, you can alias to that using the Vercel dashboard. Checkout my deployment at https://ripal.klmntn.com/.