Wrapping a third-party API in your own Express server adds caching, authentication, error normalisation, and the ability to compose multiple API calls into custom endpoints. Here's how to build a production-ready wrapper around ZipMarketData.
Project Setup
mkdir realestate-api && cd realestate-api
npm init -y
npm install express axios node-cache dotenv helmet express-rate-limit
Core Wrapper Module
// src/zipmarket.js
const axios = require('axios');
const NodeCache = require('node-cache');
const cache = new NodeCache({ stdTTL: 86400 }); // 24-hour TTL
const BASE = 'https://zipmarketdata.com';
async function get(endpoint, params) {
const key = endpoint + JSON.stringify(params);
if (cache.has(key)) return cache.get(key);
const { data } = await axios.get(`${BASE}/${endpoint}`, {
params,
headers: { 'x-rapidapi-proxy-secret': process.env.ZIPMARKET_KEY },
timeout: 8000
});
cache.set(key, data);
return data;
}
module.exports = {
marketStats: (zip) => get('market-stats', { zip_code: zip }),
rentalYield: (zip, br) => get('rental-yield', { zip_code: zip, bedrooms: br || 2 }),
propertyEstimate: (zip) => get('property-estimate', { zip_code: zip }),
affordability: (metro) => get('affordability', { metro }),
};
Composite Endpoint
// server.js
require('dotenv').config();
const express = require('express');
const zm = require('./src/zipmarket');
const app = express();
app.get('/analysis/:zip', async (req, res) => {
try {
const [market, rental, estimate] = await Promise.all([
zm.marketStats(req.params.zip),
zm.rentalYield(req.params.zip),
zm.propertyEstimate(req.params.zip),
]);
res.json({ zip: req.params.zip, market, rental, estimate });
} catch (e) {
res.status(e.response?.status || 500).json({ error: e.message });
}
});
app.listen(3000, () => console.log('Listening on :3000'));