🚪 The Proxy Layer: Your App’s Secret Doorman
Imagine your Next.js app is a fancy hotel. Guests (requests) arrive at the front door, but before they enter, there’s a doorman who decides:
- Where should this guest go?
- Should we send them somewhere else?
- Can we change their outfit before they enter?
- Can we wrap their luggage differently when they leave?
That doorman is the Proxy Layer! Let’s meet this helpful friend.
🎯 What is a Proxy?
Think of a proxy like a translator between you and a friend who speaks a different language.
You → Proxy → Friend
(translator)
In Next.js, the proxy sits between your app and external services (like APIs). It catches requests, modifies them if needed, and sends them on their way.
Real Life Example:
- You want pizza from an Italian restaurant
- The proxy takes your order
- It translates “pizza” to “pizza margherita, per favore”
- Sends it to the restaurant
- Returns with your food!
📄 The proxy.ts File
This is where our doorman lives! It’s a special file in your Next.js project.
Where Does It Live?
your-project/
├── src/
│ ├── app/
│ └── proxy.ts ← Here!
Basic Structure
// proxy.ts
export default function proxy(request) {
// Decide what to do
// with each request
return response;
}
Simple Analogy:
The proxy.ts file is like a recipe book for your doorman. It tells him exactly what to do when different types of guests arrive.
🔍 Proxy Matching
How does our doorman know which guests to help? Matching!
Pattern Matching
Think of it like a game of “Does this match?”
// Match all API requests
if (request.url.startsWith('/api/')) {
// Handle API requests
}
// Match specific paths
if (request.url === '/users') {
// Handle users endpoint
}
Wildcards
Sometimes we need to match many things at once:
// Match /api/users, /api/posts, etc.
'/api/*'
// Match /v1/users/123/profile
'/v1/users/*/profile'
Like Playing Cards:
*is like a wild card - it matches anything!/api/*matches/api/cats,/api/dogs,/api/unicorns
↩️ Redirects in Proxy
Sometimes our doorman says: “Wrong door! Go over there!”
What is a Redirect?
A redirect tells the browser: “This page moved. Go to this new address instead.”
// Old URL → New URL
if (request.url === '/old-page') {
return redirect('/new-page');
}
Types of Redirects
| Code | Meaning | Like… |
|---|---|---|
| 301 | Moved forever | “We moved house permanently!” |
| 302 | Moved temporarily | “We’re visiting grandma’s house” |
| 307 | Same method | “Go there, but knock the same way” |
Example
export function handleRedirect(request) {
const url = request.url;
// Permanent redirect
if (url === '/blog-old') {
return Response.redirect(
'/blog',
301
);
}
}
The Browser’s POV:
- User clicks
/blog-old - Proxy says “Go to
/bloginstead!” - Browser updates the address bar
- User sees the new page
🔄 Rewrites in Proxy
This is the sneaky trick! Unlike redirects, rewrites happen secretly.
Redirect vs Rewrite
REDIRECT: User sees new URL
REWRITE: User sees OLD URL, gets NEW content
Think of it like:
- Redirect: “Go to the other restaurant”
- Rewrite: “Stay here, we’ll secretly get food from the other restaurant”
Why Use Rewrites?
- Hide ugly API URLs
- Keep URLs clean for users
- Connect to external services secretly
Example
export function handleRewrite(request) {
// User visits /products
// But actually gets data from
// external API
if (request.url === '/products') {
return fetch(
'https://api.store.com/items'
);
}
}
The Magic:
- User visits
yoursite.com/products - Proxy secretly fetches from
api.store.com/items - User still sees
yoursite.com/products - Content comes from external API!
✏️ Request Modification
Before sending a request forward, we can change it!
What Can We Modify?
graph TD A["Original Request"] --> B["Proxy"] B --> C["Add Headers"] B --> D["Change URL"] B --> E["Add Auth Token"] B --> F["Modify Body"] C --> G["Modified Request"] D --> G E --> G F --> G
Adding Headers
function modifyRequest(request) {
// Clone and modify
const newHeaders = new Headers(
request.headers
);
// Add secret key
newHeaders.set(
'X-API-Key',
'secret123'
);
return new Request(request.url, {
headers: newHeaders
});
}
Adding Authentication
function addAuth(request) {
const headers = new Headers(
request.headers
);
// Add bearer token
headers.set(
'Authorization',
'Bearer ' + getToken()
);
return new Request(request.url, {
method: request.method,
headers: headers,
body: request.body
});
}
Why Modify Requests?
- Add API keys (so users don’t see them!)
- Add user authentication
- Transform data format
- Add tracking information
📤 Response Modification
The doorman can also wrap gifts differently before handing them back!
What Can We Change?
graph TD A["Original Response"] --> B["Proxy"] B --> C["Change Headers"] B --> D["Transform Body"] B --> E["Add CORS"] B --> F["Cache Control"] C --> G["Modified Response"] D --> G E --> G F --> G
Modifying Headers
async function modifyResponse(
request
) {
// Get original response
const response = await fetch(
request
);
// Create new headers
const headers = new Headers(
response.headers
);
// Add CORS header
headers.set(
'Access-Control-Allow-Origin',
'*'
);
return new Response(
response.body,
{ headers }
);
}
Transforming Response Body
async function transformBody(
request
) {
const response = await fetch(
request
);
const data = await response.json();
// Add extra info
const enhanced = {
...data,
timestamp: Date.now(),
source: 'proxy'
};
return new Response(
JSON.stringify(enhanced),
{
headers: {
'Content-Type':
'application/json'
}
}
);
}
Real Examples:
- Add caching headers
- Remove sensitive data before sending
- Add CORS headers for cross-origin requests
- Compress response data
🎨 Complete Proxy Example
Let’s put it all together!
// proxy.ts
export default async function proxy(
request: Request
) {
const url = new URL(request.url);
// 1. REDIRECT old paths
if (url.pathname === '/old') {
return Response.redirect(
'/new',
301
);
}
// 2. REWRITE API calls
if (url.pathname.startsWith('/api/')) {
const apiUrl =
'https://backend.com' +
url.pathname;
// 3. MODIFY REQUEST
const newReq = new Request(apiUrl, {
method: request.method,
headers: {
...request.headers,
'X-API-Key': 'secret'
},
body: request.body
});
// 4. Get response
const res = await fetch(newReq);
// 5. MODIFY RESPONSE
const headers = new Headers(
res.headers
);
headers.set(
'X-Powered-By',
'My Proxy'
);
return new Response(res.body, {
status: res.status,
headers
});
}
// Default: pass through
return fetch(request);
}
🌟 Quick Summary
| Concept | What It Does | Analogy |
|---|---|---|
| Proxy | Middleman for requests | Translator |
| proxy.ts | Configuration file | Doorman’s rulebook |
| Matching | Find which requests to handle | ID checking |
| Redirect | Send to new URL (visible) | “Go next door” |
| Rewrite | Secretly fetch from elsewhere | Secret food delivery |
| Request Mod | Change outgoing request | Add secret note |
| Response Mod | Change incoming response | Rewrap the gift |
💡 Remember This!
The Proxy Layer is your app’s helpful doorman.
It decides where requests go, can secretly fetch from other places, and can dress up both requests and responses before they reach their destination.
You now understand the Proxy Layer! 🎉
Next time you need to:
- Hide API keys → Use Request Modification
- Clean up URLs → Use Rewrites
- Move old pages → Use Redirects
- Add headers → Use Response Modification
Your doorman has got your back! 🚀
