DEV Community

loading...
Cover image for Implementing a serverless API proxy in 10 minutes
ScaleDynamics

Implementing a serverless API proxy in 10 minutes

domis66 profile image Dominique Péré Originally published at Medium Updated on ・8 min read

This article has been updated on May 26th, 2020, following the latest release of WarpJS serverless.

Serverless has become a hot topic lately, as it offers auto-scaling, flexibility, and a shorter time to release. If like me you don't want to manage servers on a daily basis but rather focus on the features' code, serverless is an option you might want to consider.

Serverless is most commonly used for web applications and back ends, but also for data processing. By the way, there is a lot of noise and confusion about what serverless is, so, to be precise, I only mean Function-as-a-Service (or FaaS) when speaking about serverless here.

Most JavaScript full-stack developers develop their applications with React, Vue.js, or Angular, served by Node.js + Express. With the serverless approach, I see the opportunity of making development iterations shorter to free up time for what matters: the features' code.

In this post, I will explain how to implement a proxy server for REST APIs within a few minutes using a serverless platform.

Why would I implement a serverless API proxy?

In my use case, I wanted to create an app to request the GitHub Search API and NPM at once. I wanted to perform a search on JavaScript + TypeScript repositories to display GitHub stars and the NPM weekly downloads in the same view. It's useful to make a basic evaluation of package popularity.

We could do all this job in a browser. So why should we create a serverless HTTP proxy on top of the GitHub and NPM APIs?

Reason 1: security. API keys cannot lie in the front-end code. Malicious developers could use it to access my account, I would expose myself to renew it frequently or to be blocked by the API provider. Also, the Cross-Origin Resource Sharing (CORS) is blocked by many providers. In both situations, there's no choice than to implement a proxy server.

Reason 2: performance. To make my GitHub+NPM data feature available, we need to request GitHub twice and NPM a lot. My browser would then perform multiple requests for each user search. A proxy server in the cloud will have much lower latency and larger bandwidth to perform these requests faster. Additionally, the JSON returned by APIs contains much more data than we need. We only need from the GitHub API 7 properties and not the 50+ the original endpoints return for each repo.

Reason 3: separation of concerns. Whenever an API is updated, go down or I want to switch for another instead, my client code remains unchanged, I will only change my serverless functions' code.

Some other reasons to implement a proxy server include API modernization, caching, resilience, and error management, but it's another topic.

You may argue those are reasons to implement a proxy, not reasons to run it on a serverless platform, and you may be right. However, an API proxy is by definition a piece of our architecture that needs to be very elastic. It takes the first hit behind a user click so it needs to be ready to scale as the number of users grows. Good news: serverless scales horizontally by design, we won't need to know anything about Docker or Kubernetes to scale and fit with the traffic.

Now, let's see how we can implement that API proxy. To this end, I could use any serverless platform, such as AWS Lambda or Google Functions. However, I recently joined the company powering WarpJS serverless and I have to admit that their stack, built on top of the cloud providers, saves many steps like the serverless function declarations, the endpoint management or the deployment to a public URL. This JavaScript serverless platform is kind of all-in-one: front end and back end are deployed at once.

Let's get to it now!

Steps to turn a native JavaScript function into a serverless function

Prerequisites

Stack

  • Vue.js
  • Axios
  • WarpJS serverless

Together, we will go through the different steps of initializing our GitHub Search project, walk through the specific GitHub+NPM search feature we want, and see how to turn a pure JavaScript function - here the search function - into a serverless function that will behave as an HTTP proxy. We will run everything on our local computer before deploying both front end and back end on a cloud platform with a command-line to get a live URL.

We have developed a small Vue.js application to list the repositories matching a certain keyword. Here is what it looks like:

a serverless app to search for JS+TS projects on GitHub displaying

We can download this project using the following command-line

$ git clone https://github.com/WarpJS/github-repo-search.git 

...and set up our project

$ cd github-repo-search
$ npm install

While it's downloading, let's have a look under the hood. If you have any trouble with node-gyp after install, see the official "node-gyp" installation doc.

The back-end serverless function

First, the back end. The script api/index.js contains only the server-side logic, No HTTP, no endpoint, no argument control, no serialization: only the function "juice".

/**
* Search repositories
*
* @param {string} query
* @param {number} page
*/

const search = async (query, page = 1) => {
  ...
};

module.exports = { search };

The "search" function needs to be exported to tell WarpJS it needs to be exposed as a serverless function. After deployment, such functions will run on Node.js on your preferred serverless platform, such as AWS Lambda, Google functions, or others as long as WarpJS serverless supports it.

The helper module to call the serverless function

Next, we need a way to tie our front end to our soon-to-be-deployed serverless function. This is the job of WarpJS. To do this, we first need to create a WarpJS account, as the builder also deals with cloud serverless FaaS providers: that’s why you need a cloud account (this step also prevents you from creating an AWS or a GCP account).

If you don’t already have one, you request a WarpJS serverless account. As I write these lines, WarpJS is in private beta, so I just gave you my personal invitation link. Please make good use of it ;) Then you just need to log in to WarpJS within your terminal:

$ npx warp login

It saves your credentials to a local file so you only need to do this once for all your projects.

The following command-line calls "npx warp build", which creates a JavaScript helper module for the client (a "stub") according to the configuration set in the api/warp.config.js. Here, we generate it as an npm module in the parent project, but we could output it as a JavaScript file as well, and import it with a tag, as detailed in the doc.

Run this command-line to generate a serverless adapter as a module in our client project:

$ npm run build

This is replacing the HTTP layer. We don’t need to refer to an API doc nor to code any HTTP request. Our client file is now ready to be imported into any JavaScript project.

The Front end

The front end is a classic Vue.js single page app with a search box followed by a list when the results come. We would find details about the front-end app in the app.vue file. We import the "github-repo-search-api" module, a "stub" to call our serverless function.

// init WarpJS
import Warp from 'github-repo-search-api';
const api = new Warp();
...
// fetch api with warp
const { repositories, total, error } = await api.search(this.search);

The "api" object, an instance of Warp, is our FaaS adapter - our helper module - to call our serverless function. This way it is super easy to call any back-end function with no HTTP headache, no endpoint codification, no argument serialization, and no response deserialization.

How to run a serverless function on a local environment

Before we can run this code, we first need to generate an access token for GitHub

Generate a GitHub access token

We need to authenticate to generate a GitHub access token that will be used in our application.

  • Navigate to GitHub to generate a new access token
  • Give it a name
  • Only check the "public_repo" scope (this is all we need in our example)
  • Generate Token
  • Get back to the api/index.js and replace YOUR_API_TOKEN with yours.
// ./src/api.js

// GitHub auth token
const GITHUB_ACCESS_TOKEN = 'YOUR_API_TOKEN';

Local Run

We're all set, let's now test locally. We open a terminal in the project folder and run

$ npm run dev

This opens our app in a new browser's tab. We can take a minute to play with it...

At any time, we can change the code and save, the session refreshes the browser, so we don't have to relaunch our local server thanks to a live reload feature. Actually, in development mode, the WarpJS serverless emulator dynamically injects the functions in the server to prevent it from rebuilding and restarting. This saves us a lot of time on the development/debugging phase. Feel free to make any changes you wish to customize our little app.

The local run is cool to test, but let's deploy now.

How to run a proxy in a serverless environment

All we need now is to build our project, front and back ends:

$ npm run build

... and then, the awesome command-line to deploy it all at once 🤓

$ npm run deploy
> github-repo-search@1.0.0 deploy /Users/dom/src/github-repo-search
> warp-deploy --asset-dir=dist .

Deploying..............................
Deployed project 'github-repo-search' at:
https://warpjs-xxxxxxxxxxxxxx.storage.googleapis.com/index.html

And it's done! Our web app is now live on a public URL. We can copy/paste the last line in our favorite browser and share it with coworkers or friends.

As we can see in the URL, it's deployed on GCP. WarpJS runs above the cloud providers, so we can run it where we need to.

Regarding the cloud credits, the beta version does limit usage with a strict limit, just "fair use". Whatever, it's all free for now 🤑

If you want to get inspiration to develop some other kind of serverless app, we have a bunch of serverless code samples to deal with authentication, storage, and even in-browser Machine Learning...

As I write this article, WarpJS is still in the beta stage but the platform will soon offer options to:

  • deploy on a customized domain name (removing the banner by the way)
  • deploy on multiple clouds for the same function such as AWS Lambda and Azure function serverless platforms,
  • deploy on-premise or on hybrid cloud.

Those are probably topics for a next post 😁

I hope you enjoyed this reading, learned, had fun, and you now like serverless as much as I do. Feel free to comment on this article to let me know what you think or to share your experience.

Credits

Big thanks to Nicolas Pennec who developed the app we took as an example. He is a JavaScript Expert in ScaleDynamics. He co-organizes RennesJS, a French JavaScript Meetup, so if you come by Brittany you're more than welcome to join us!

Discussion

pic
Editor guide
Collapse
sophek profile image
sophek

Thanks for this tutorial. Quick question how do I consume the serverless function apart from warpjs?

const hello = (name) => {
// warp directive
'warp +server -client'

return Hello ${name} from Node.js ${process.version}
}

Could I go to xxxxxxxx.url/hello? or something?

Collapse
domis66 profile image
Dominique Péré Author

Hi Sophek, actually WarpJS does not expose an HTTP REST API on top of the function. It uses its own protocol to wrap the function parameters (that may not be primitive types) and required context elements to run it serverless. When done, it returns also the result (again, maybe an object) to get back to the awaiting front-end context. Both frontend and backend need to be coded in JavaScript, but you can use any framework.

Collapse
Sloan, the sloth mascot
Comment deleted
Collapse
sophek profile image
sophek

Thank you, This is a promising technology. I'll be willing to help in any way, I'm a vuejs / javascript developer and designer, and also a documentary filmmaker and video editor. Let me know if I can help in promoting this tech. I can probably use this tech in my Cleanvid project. cleanvid.org, the site is not done yet.

Thread Thread
domis66 profile image
Dominique Péré Author

Thank you for your proposition :) That's awesome. Let's talk in private then.