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'));