Photo by Harry Gillen on Unsplash
How to fetch API from backend using vercel's serverless functions
A beginner-friendly tutorial from a beginner
Imagine you're a fresh naïve junior frontend dev who's working on your first personal project outside of course materials.
You think to yourself:
There's plenty to learn just in frontend alone, I'll stick to frontend for now and learn backend later. Besides, with the ability to fetch data from APIs that's enough ammunition to build dope apps! Probably won't be touching backend anytime soon.
Then the internet hits you with that...
CORS ERROR.
Well, that happened to me.
Why don't we just fetch API using frontend?
Because CORS error
Because you want to keep your API key secure
So what do we want to happen?
User inputs query on the frontend
An API request is sent from the frontend to the backend sever
The backend server fetches the data from the API
The server returns the data to the frontend
Happy days
⚠️ Note: This tutorial assumes you already have a vercel project setup and/or linked to your github repo ie. you know how to deploy updates to vercel. If not see this article to get started with vercel.
Step 1: Setup
First we'll have to install the required packages.
axios - an alternative to the native
fetch
function (optional)express - creates the server
dotenv - to keep your API keys secret
cors - to deal with CORS
Go to your project's root folder, then in the terminal run:
npm install axios express cors dotenv
Then in your project root folder, create a new folder called api
(must be exactly this for deploying to vercel). Inside of that folder, create a new file called index.js
.
To do this via the terminal, assuming you're already in your project root folder, run
mkdir api
touch api/index.js
In index.js
, paste the following code to create an express "server".
// Load packages
const express = require('express')
const cors = require('cors')
require('dotenv').config()
const axios = require('axios')
// Create express server
const app = express()
Step 2: Enable CORS
Then paste the following code to enable CORS. The *
means any origin is allowed. Please see this article for alternate methods to enable CORS on vercel.
app.use(
cors({
origin: '*',
})
)
Step 3: Create our backend serverless API functions
Ok, we're now going to use vercel's serverless functions feature.
Here's my basic understanding of it:
Typically we could set up a server that's running constantly 24/7 listening for api requests - but that can be expensive.
Vercel instead offers serverless functions which runs code on-demand. Basically it's like a pop-up shop that only sets up when there's a customer (a request is made). After it successfully serves the customer, it disappears, poof. The benefit is that it's cheaper (free or paid depending on how long it takes the function to finish executing) and we don't need to manage things like infrastructure etc.
If you want to understand vercel serverless functions better I recommend watching this video
In the following code, we'll create two api endpoints.
'/api'
- this is the root endpoint which will point to example.com/api'/api/smart-floor-price'
- this endpoint will point to example.com/api/smart-floor-price (you can rename'smart-floor-price'
to whatever your want)
// req = request, res = response
app.get('/api', (req, res) => {
res.setHeader('Content-Type', 'text/html')
res.setHeader('Cache-Control', 's-max-age=1, stale-while-revalidate')
res.send('hi wyd') // optional message
})
The following function for the 'smart-floor-price'
endpoint will,
take in a request from the frontend (we'll sort out the frontend later),
read the request's parameters,
forward the request to the 3rd-party api and fetch the data
return the data to the frontend
To create more endpoints simply duplicate this function and change the endpoint name and the appropriate settings for fetching api.
app.get('/api/smart-floor-price', (req, res) => {
async function getSmartFloorPrice(contractAddress) {
try {
const config = {
method: 'GET',
headers: { Authorization: `Bearer ${process.env.YOUR_API_KEY}` },
url: `https://api.rarify.tech/data/contracts/ethereum:${contractAddress}/smart-floor-price`,
}
const data = await axios(config).then((res) => res.data)
res.json(data)
} catch (err) {
console.log(err)
}
}
const contractAddress = req.query.contractAddress // this is how to get the request parameters from the frontend
getSmartFloorPrice(contractAddress)
})
We're almost done! Add the following code at the end of index.js
.
module.exports = app
Step 4: add some code to vercel.json
Paste the following code in your vercel.json
file. If you don't have one, create one in the root folder.
{
"rewrites": [{ "source": "/api/(.*)", "destination": "/api" }]
}
Now you're ready to save your files and deploy to vercel!
Full code for api/index.js
const express = require('express')
const cors = require('cors')
require('dotenv').config()
const axios = require('axios')
const app = express()
app.use(
cors({
origin: '*',
})
)
app.get('/api', (req, res) => {
res.setHeader('Content-Type', 'text/html')
res.setHeader('Cache-Control', 's-max-age=1, stale-while-revalidate')
res.send('hi wyd')
})
app.get('/api/smart-floor-price', (req, res) => {
async function getSmartFloorPrice(contractAddress) {
try {
const config = {
method: 'GET',
headers: { Authorization: `Bearer ${process.env.YOUR_API_KEY}` },
url: `https://api.rarify.tech/data/contracts/ethereum:${contractAddress}/smart-floor-price`,
}
const data = await axios(config).then((res) => res.data)
res.json(data)
} catch (err) {
console.log(err)
}
}
const contractAddress = req.query.contractAddress
getSmartFloorPrice(contractAddress)
})
module.exports = app
Final step: Use your brand spanking new apis in your frontend
After deploying your serverless functions to vercel, simply fetch data from the frontend using the your app's vercel url. For example it'll be something like this in your frontend script:
async function getSmartFloorPrice(contractAddress) {
try {
const config = {
method: 'GET',
url: `https://your-app.vercel.app/api/smart-floor-price`,
params: {
contractAddress: contractAddress,
},
}
const data = await axios(config).then((res) => res.data)
return data
} catch (err) {
console.log(err)
}
}