-
Notifications
You must be signed in to change notification settings - Fork 3
feat: trend beta & liquidations endpoint #281
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
c81a852
fcd2fa8
e6d4902
2123424
d3930fa
8f7c1de
b124ebb
ffe5955
31a92d8
7890da2
bb0b84e
95b63ac
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| import { type NextRequest, NextResponse } from 'next/server'; | ||
| import { MONARCH_API_KEY, getMonarchUrl } from '../utils'; | ||
|
|
||
| export async function GET(req: NextRequest) { | ||
| if (!MONARCH_API_KEY) { | ||
| console.error('[Monarch Liquidations API] Missing MONARCH_API_KEY'); | ||
| return NextResponse.json({ error: 'Server configuration error' }, { status: 500 }); | ||
| } | ||
|
|
||
| const chainId = req.nextUrl.searchParams.get('chain_id'); | ||
|
|
||
| try { | ||
| const url = getMonarchUrl('/v1/liquidations'); | ||
| if (chainId) url.searchParams.set('chain_id', chainId); | ||
|
|
||
| const response = await fetch(url, { | ||
| headers: { 'X-API-Key': MONARCH_API_KEY }, | ||
| next: { revalidate: 300 }, | ||
| }); | ||
|
|
||
| if (!response.ok) { | ||
| const errorText = await response.text(); | ||
| console.error('[Monarch Liquidations API] Error:', response.status, errorText); | ||
| return NextResponse.json({ error: 'Failed to fetch liquidations' }, { status: response.status }); | ||
| } | ||
|
|
||
| return NextResponse.json(await response.json()); | ||
| } catch (error) { | ||
| console.error('[Monarch Liquidations API] Failed to fetch:', error); | ||
| return NextResponse.json({ error: 'Failed to fetch liquidations' }, { status: 500 }); | ||
| } | ||
|
Comment on lines
+12
to
+31
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: cat -n app/api/monarch/liquidations/route.tsRepository: antoncoding/monarch Length of output: 1745 🌐 Web query:
💡 Result: Summary — best practices for timeouts in Next.js 15 Route Handlers (fetch + AbortController)
Relevant references
If you want, I can paste a minimal example route.ts showing: combining req.signal + timeout controller, passing signal to fetch, cleanup, and using waitUntil for background work. Add timeout + guard JSON parsing to prevent hanging and crashes on invalid upstream responses. No timeout allows indefinite resource exhaustion if the upstream stalls; Proposed diff try {
- const response = await fetch(url, {
+ const controller = new AbortController();
+ const timeoutId = setTimeout(() => controller.abort(), 10_000);
+
+ const response = await fetch(url, {
headers: { 'X-API-Key': MONARCH_API_KEY },
next: { revalidate: 300 }, // Cache for 5 minutes
+ signal: controller.signal,
});
+ clearTimeout(timeoutId);
@@
- return NextResponse.json(await response.json());
+ let data: unknown;
+ try {
+ data = await response.json();
+ } catch {
+ console.error('[Monarch Liquidations API] Upstream returned non-JSON payload');
+ return NextResponse.json({ error: 'Failed to fetch liquidations' }, { status: 502 });
+ }
+ return NextResponse.json(data);
} catch (error) {For Next.js 15, this AbortController + setTimeout pattern is the standard way to set per-request timeouts. Works cleanly with 🤖 Prompt for AI Agents |
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| import { type NextRequest, NextResponse } from 'next/server'; | ||
| import { MONARCH_API_KEY, getMonarchUrl } from '../utils'; | ||
|
|
||
| export async function GET(req: NextRequest) { | ||
| if (!MONARCH_API_KEY) { | ||
| console.error('[Monarch Metrics API] Missing MONARCH_API_KEY'); | ||
| return NextResponse.json({ error: 'Server configuration error' }, { status: 500 }); | ||
| } | ||
|
|
||
| const searchParams = req.nextUrl.searchParams; | ||
|
|
||
| try { | ||
| const url = getMonarchUrl('/v1/markets/metrics'); | ||
| for (const key of ['chain_id', 'sort_by', 'sort_order', 'limit', 'offset']) { | ||
| const value = searchParams.get(key); | ||
| if (value) url.searchParams.set(key, value); | ||
| } | ||
|
antoncoding marked this conversation as resolved.
|
||
|
|
||
| const response = await fetch(url, { | ||
| headers: { 'X-API-Key': MONARCH_API_KEY }, | ||
| cache: 'no-store', | ||
| }); | ||
|
|
||
| if (!response.ok) { | ||
| const errorText = await response.text(); | ||
| console.error('[Monarch Metrics API] Error:', response.status, errorText); | ||
| return NextResponse.json({ error: 'Failed to fetch market metrics' }, { status: response.status }); | ||
| } | ||
|
|
||
| return NextResponse.json(await response.json()); | ||
| } catch (error) { | ||
| console.error('[Monarch Metrics API] Failed to fetch:', error); | ||
| return NextResponse.json({ error: 'Failed to fetch market metrics' }, { status: 500 }); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| export const MONARCH_API_ENDPOINT = process.env.MONARCH_API_ENDPOINT; | ||
| export const MONARCH_API_KEY = process.env.MONARCH_API_KEY; | ||
|
|
||
| export const getMonarchUrl = (path: string): URL => { | ||
| if (!MONARCH_API_ENDPOINT) throw new Error('MONARCH_API_ENDPOINT not configured'); | ||
| return new URL(path, MONARCH_API_ENDPOINT.replace(/\/$/, '')); | ||
| }; | ||
|
antoncoding marked this conversation as resolved.
|
||
Uh oh!
There was an error while loading. Please reload this page.