Repository: bradtraversy/node-api-proxy-server
Branch: main
Commit: deef7d7e53ab
Files: 10
Total size: 7.0 KB
Directory structure:
gitextract_mxqabiz3/
├── .gitignore
├── MIT-LICENSE.txt
├── index.js
├── middleware/
│ └── error.js
├── package.json
├── public/
│ ├── index.html
│ ├── main.js
│ └── style.css
├── readme.md
└── routes/
└── index.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
node_modules
.env
================================================
FILE: MIT-LICENSE.txt
================================================
Copyright (c) 2021 Brad Traversy
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: index.js
================================================
const express = require('express')
const cors = require('cors')
const rateLimit = require('express-rate-limit')
require('dotenv').config()
const errorHandler = require('./middleware/error')
const PORT = process.env.PORT || 5000
const app = express()
// Rate limiting
const limiter = rateLimit({
windowMs: 10 * 60 * 1000, // 10 Mins
max: 100,
})
app.use(limiter)
app.set('trust proxy', 1)
// Enable cors
app.use(cors())
// Set static folder
app.use(express.static('public'))
// Routes
app.use('/api', require('./routes'))
// Error handler middleware
app.use(errorHandler)
app.listen(PORT, () => console.log(`Server running on port ${PORT}`))
================================================
FILE: middleware/error.js
================================================
const errorHandler = (err, req, res, next) => {
console.log(123)
if (res.headersSent) {
return next(err)
}
res.status(500).json({
success: false,
error: err.message || 'Server Error',
stack: process.env.NODE_ENV === 'production' ? undefined : err.stack,
})
}
module.exports = errorHandler
================================================
FILE: package.json
================================================
{
"name": "api-proxy-server",
"version": "1.0.0",
"description": "Proxy server to hide public API keys with rate limiting, caching",
"main": "index.js",
"scripts": {
"start": "node index",
"dev": "nodemon index"
},
"author": "Brad Traversy",
"license": "MIT",
"dependencies": {
"apicache": "^1.6.2",
"cors": "^2.8.5",
"dotenv": "^10.0.0",
"express": "^4.17.1",
"express-rate-limit": "^5.5.0",
"needle": "^3.0.0"
},
"devDependencies": {
"nodemon": "^2.0.14"
}
}
================================================
FILE: public/index.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="style.css" />
<title>Weather App</title>
</head>
<body>
<div class="container">
<div class="weather"></div>
<form id="weather-form">
<input type="text" id="city-input" placeholder="Enter a city" />
<button type="submit">Submit</button>
</form>
</div>
<script src="main.js"></script>
</body>
</html>
================================================
FILE: public/main.js
================================================
const weatherDisplay = document.querySelector('.weather')
const weatherForm = document.querySelector('#weather-form')
const cityInput = document.querySelector('#city-input')
// Fetch weather data from API
const fetchWeather = async (city) => {
const url = `/api?q=${city}`
const res = await fetch(url)
const data = await res.json()
if (data.cod === '404') {
alert('City not found')
return
}
if (data.cod === 401) {
alert('Invalid API Key')
return
}
const displayData = {
city: data.name,
temp: kelvinToFahrenheit(data.main.temp),
}
addWeatherToDOM(displayData)
}
// Add display data to DOM
const addWeatherToDOM = (data) => {
weatherDisplay.innerHTML = `
<h1>Weather in ${data.city}</h1>
<h2>${data.temp} °F</h2>
`
cityInput.value = ''
}
// Convert Kelvin to Fahrenheit
const kelvinToFahrenheit = (temp) => {
return Math.ceil(((temp - 273.15) * 9) / 5 + 32)
}
// Event listener for form submission
weatherForm.addEventListener('submit', (e) => {
e.preventDefault()
if (cityInput.value === '') {
alert('Please enter a city')
} else {
fetchWeather(cityInput.value)
}
})
// Initial fetch
fetchWeather('Miami')
================================================
FILE: public/style.css
================================================
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;700&display=swap');
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Poppins', sans-serif;
line-height: 1.6;
background-color: steelblue;
color: #fff;
}
h2 {
font-size: 3rem;
font-weight: 600;
margin-bottom: 1.5rem;
font-weight: bold;
}
.container {
max-width: 500px;
margin: 100px auto;
text-align: center;
}
input {
width: 100%;
padding: 10px;
border: none;
border-bottom: 2px solid #fff;
background-color: transparent;
color: #fff;
font-size: 1.5rem;
font-weight: bold;
}
input:focus {
outline: none;
}
input::placeholder {
color: #fff;
}
button {
padding: 13px;
width: 300px;
border: none;
background-color: #000;
color: #fff;
margin-top: 30px;
}
button:hover {
background-color: #fff;
color: #000;
cursor: pointer;
}
================================================
FILE: readme.md
================================================
# Node API Proxy Server
Server used for hiding API keys, rate limiting and caching. This uses the [OpenWeather API](https://openweathermap.org/api) but you can easily change it to whatever public API you are using
## Usage
### Install dependencies
```bash
npm install
```
### Run on http://localhost:5000
```bash
npm run dev
```
### Add public API info
Rename **.env.example** to **.env** and edit the values
If the public API URL is **https://api.openweathermap.org/data/2.5/weather?q={city}&appid={APIkey}**
- API_BASE_URL = "https://api.openweathermap.org/data/2.5/weather"
- API_KEY_NAME = "appid"
- API_KEY_VALUE = "YOUR API KEY"
You can add on any other query params as needed when hitting the /api endpoint such as https://yourdomain/api?q=detroit without having to add your key in the client
- Add new routes as you see fit
- Change rate limiting and caching to desired values
This project is from this [YouTube tutorial](https://youtu.be/ZGymN8aFsv4)
================================================
FILE: routes/index.js
================================================
const url = require('url')
const express = require('express')
const router = express.Router()
const needle = require('needle')
const apicache = require('apicache')
// Env vars
const API_BASE_URL = process.env.API_BASE_URL
const API_KEY_NAME = process.env.API_KEY_NAME
const API_KEY_VALUE = process.env.API_KEY_VALUE
// Init cache
let cache = apicache.middleware
router.get('/', cache('2 minutes'), async (req, res, next) => {
try {
const params = new URLSearchParams({
[API_KEY_NAME]: API_KEY_VALUE,
...url.parse(req.url, true).query,
})
const apiRes = await needle('get', `${API_BASE_URL}?${params}`)
const data = apiRes.body
// Log the request to the public API
if (process.env.NODE_ENV !== 'production') {
console.log(`REQUEST: ${API_BASE_URL}?${params}`)
}
res.status(200).json(data)
} catch (error) {
next(error)
}
})
module.exports = router
gitextract_mxqabiz3/
├── .gitignore
├── MIT-LICENSE.txt
├── index.js
├── middleware/
│ └── error.js
├── package.json
├── public/
│ ├── index.html
│ ├── main.js
│ └── style.css
├── readme.md
└── routes/
└── index.js
SYMBOL INDEX (4 symbols across 2 files) FILE: index.js constant PORT (line 7) | const PORT = process.env.PORT || 5000 FILE: routes/index.js constant API_BASE_URL (line 8) | const API_BASE_URL = process.env.API_BASE_URL constant API_KEY_NAME (line 9) | const API_KEY_NAME = process.env.API_KEY_NAME constant API_KEY_VALUE (line 10) | const API_KEY_VALUE = process.env.API_KEY_VALUE
Condensed preview — 10 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (8K chars).
[
{
"path": ".gitignore",
"chars": 17,
"preview": "node_modules\n.env"
},
{
"path": "MIT-LICENSE.txt",
"chars": 1056,
"preview": "Copyright (c) 2021 Brad Traversy\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this s"
},
{
"path": "index.js",
"chars": 653,
"preview": "const express = require('express')\nconst cors = require('cors')\nconst rateLimit = require('express-rate-limit')\nrequire("
},
{
"path": "middleware/error.js",
"chars": 317,
"preview": "const errorHandler = (err, req, res, next) => {\n console.log(123)\n if (res.headersSent) {\n return next(err)\n }\n\n "
},
{
"path": "package.json",
"chars": 521,
"preview": "{\n \"name\": \"api-proxy-server\",\n \"version\": \"1.0.0\",\n \"description\": \"Proxy server to hide public API keys with rate l"
},
{
"path": "public/index.html",
"chars": 598,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta http-equiv=\"X-UA-Compatible\" content=\"I"
},
{
"path": "public/main.js",
"chars": 1198,
"preview": "const weatherDisplay = document.querySelector('.weather')\nconst weatherForm = document.querySelector('#weather-form')\nco"
},
{
"path": "public/style.css",
"chars": 901,
"preview": "@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;700&display=swap');\n\n* {\n margin: 0;\n p"
},
{
"path": "readme.md",
"chars": 973,
"preview": "# Node API Proxy Server\n\nServer used for hiding API keys, rate limiting and caching. This uses the [OpenWeather API](htt"
},
{
"path": "routes/index.js",
"chars": 914,
"preview": "const url = require('url')\nconst express = require('express')\nconst router = express.Router()\nconst needle = require('ne"
}
]
About this extraction
This page contains the full source code of the bradtraversy/node-api-proxy-server GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 10 files (7.0 KB), approximately 2.2k tokens, and a symbol index with 4 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.