Next.js Discord

Discord Forum

API Routes on the App Router (Pre-Rendering Error?)

Answered
Little fire ant posted this in #help-forum
Open in Discord
Little fire antOP
info  - Need to disable some ESLint rules? Learn more here: https://nextjs.org/docs/basic-features/eslint#disabling-rules
 ✓ Linting and checking validity of types
 ✓ Collecting page data
   Generating static pages (2/15)  [==  ]

Error occurred prerendering page "/api/ranks/tribe_ranks". Read more: https://nextjs.org/docs/messages/prerender-error
Error: connect ECONNREFUSED ::1:3306
    at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1481:16)
    at TCPConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17)
    --------------------
    at Protocol._enqueue (/home/debian/bloody-ark-v4/node_modules/mysql/lib/protocol/Protocol.js:144:48)
    at Protocol.handshake (/home/debian/bloody-ark-v4/node_modules/mysql/lib/protocol/Protocol.js:51:23)
    at Connection.connect (/home/debian/bloody-ark-v4/node_modules/mysql/lib/Connection.js:116:18)
    at /home/debian/bloody-ark-v4/node_modules/knex/lib/dialects/mysql/index.js:66:18
    at new Promise (<anonymous>)
    at Client_MySQL.acquireRawConnection (/home/debian/bloody-ark-v4/node_modules/knex/lib/dialects/mysql/index.js:61:12)
 ✓ Generating static pages (15/15)



Code:
import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient();

export async function GET(request: Request) {
    // Get DB Creds
    const cluster = await prisma.cluster.findUnique({
        where: {
          id: "f6365f0c-0bf2-42ae-be08-0d9523f98205",
        },
    });
  

    const knex = require('knex')({
        client: 'mysql',
        connection: {
          host: cluster?.databaseUrl,
          port: cluster?.databasePort,
          user: cluster?.databaseUsername,
          password: cluster?.databasePassword,
          database: cluster?.databaseDb
        }
      });

    const ranking_data = await knex.table('advancedachievements_tribedata')
    .select('advancedachievements_tribedata.TribeID', 'advancedachievements_tribedata.TribeName', 'advancedachievements_tribedata.DamageScore')
    .leftJoin('advancedachievements_playerdata', 'advancedachievements_playerdata.TribeID', 'advancedachievements_tribedata.TribeID')
    .sum('PlayerKills as Kills')
    .sum('DeathByPlayer as Deaths')
    .sum('DinoKills as DinoKills')
    .sum('PlayTime as PlayTime')
    //.whereLike('advancedachievements_tribedata.TribeName', search)
    .groupBy('advancedachievements_tribedata.TribeID')
    //.orderBy(safeFilter, 'desc')
    .limit(20)
    .offset(20 * 1)
Answered by Shy Albatross
export const dynamic = 'force-dynamic' in app/api/ranks/tribe_ranks

/route.ts
View full answer

78 Replies

Shy Albatross
check the props of cluster before you pass those to knex because you got a connection refused error
Little fire antOP
But why is api routes prefetched?
does API Routes work on client now with App Routers?
Shy Albatross
while generating pages, it's trying to render a component that is using that API route?
Little fire antOP
yep
its not a component tho
Shy Albatross
that's the route, what I mean is you have a component somewhere on a page that's using this route and it's trying to render that page statically
Little fire antOP
Yeah that page is pre-rendered
/app/ranks/page.tsx
should I make it use a client instead?
'use client'
but it's already using that.
Shy Albatross
I don't think a page can be a client component, can it - yo ushould put Rankings in a separate file, since that is a client component, mark that as "use client" and import that into this page
Little fire antOP
I'll try that.
App Routers is giving me pain honestly
It seems to be trying to prefetch evreything "/api"
Shy Albatross
yeah that's odd
Little fire antOP
I'm trying this now
Error occurred prerendering page "/api/ranks/tribe_ranks". Read more: https://nextjs.org/docs/messages/prerender-error
Error: connect ECONNREFUSED ::1:3306
    at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1481:16)
    at TCPConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17)
    --------------------
    at Protocol._enqueue (/home/debian/bloody-ark-v4/node_modules/mysql/lib/protocol/Protocol.js:144:48)
    at Protocol.handshake (/home/debian/bloody-ark-v4/node_modules/mysql/lib/protocol/Protocol.js:51:23)
    at Connection.connect (/home/debian/bloody-ark-v4/node_modules/mysql/lib/Connection.js:116:18)
    at /home/debian/bloody-ark-v4/node_modules/knex/lib/dialects/mysql/index.js:66:18
    at new Promise (<anonymous>)
    at Client_MySQL.acquireRawConnection (/home/debian/bloody-ark-v4/node_modules/knex/lib/dialects/mysql/index.js:61:12)
 ✓ Generating static pages (15/15)

> Export encountered errors on following paths:
        /api/ranks/tribe_ranks/route: /api/ranks/tribe_ranks
testrankings is a client component
Shy Albatross
drop the import for hooks from the page since those are client-only, but that won't help I don't think
Little fire antOP
nope
Shy Albatross
your file structure looks fine, the route handler looks fine, I don't know why it would be trying to prerender an api route while calling it "a page"
Little fire antOP
knex had issues even in debugging
I had to add this to my nextjs config
const nextConfig = {
    experimental: {
        serverComponentsExternalPackages: ['knex'],
    },
}
NextJS should be able to acts an API too with app routers?
Shy Albatross
in the original Rankings component, how do you call that getRankings function?
where does it get called
Little fire antOP
Using export const dynamic = "force-dynamic"; seems to have solved it?
Shy Albatross
well that just makes it so it won't try to statically render that page
you're forcing it to be a lambda basically
in the original Rankings component, how do you call that getRankings function?
^ ?
I think you're doing something that causes it to try to fetch the api route in the server component and api routes aren't availabe during build
Little fire antOP
I'll publish the git repo
so you can have a look
@Shy Albatross > in the original Rankings component, how do you call that getRankings function?
Little fire antOP
    const getRankings = () => {
        setLoading(true); // Set loading to true when fetching data

        fetch(`/api/ranks/${activeTab}`)
            .then((res) => res.json())
            .then((data) => {
                setData(data);
                setLoading(false); // Set loading to false when data is fetched
            });
    }

    useEffect(() => {
        // Trigger a data fetch whenever activeTab changes
        getRankings();
    }, [activeTab]);
Shy Albatross
I still think the page is server component and you need to put Rankings in a separate file and mark that as "use client", since you're fetching the api route in a useEffect, so on client, I don't know why it would be trying to do anything about that, especially during build, last thing - well, two things - I can suggest is moving getRankings function inside the useEffect but even I don't believe it should change anything, and second idea is convert the tribe_ranks route handler into a server action, which then you can import into Rankings component and await that, it will do the route handler for you automagically
Little fire antOP
I did
when you say seperate file
you mean component?
Shy Albatross
yeah, in components folder, just dump
Little fire antOP
the page itself ^
page.tsx
Shy Albatross
remove the use client and the unnecessary imports from the page
idk, you have Request in your route handler, therefore it should be dynamic, not static
is it because you're not using the request?
Little fire antOP
Shy Albatross
you still have "use client" in that page
but yeah, I think it's this issue
i.e. you have Request but you're not using it so it's thinking your handler is static, put force-dynamic in the route handler or fix the handler code so it doesn't explode with connection refused
Shy Albatross
export const dynamic = 'force-dynamic' in app/api/ranks/tribe_ranks

/route.ts
Answer
Little fire antOP
HMM
yeah that was i did to fix it temporarily
Shy Albatross
unless you have request in your GE (which you do) and you actually use some dynamic props from it, it treats the route as static
Little fire antOP
Shy Albatross
since you don't read any data from the request, then it assumes it's a pure function
Little fire antOP
ahhh
So I have to use Request
for it to know it's static
Shy Albatross
if you read data from request then it will make it dynamic, or just do export const dynamic = 'force-dynamic'
or if you think it's static, then fix your props in cluster so you don't explode with connection refused from knex 😄
Little fire antOP
Yep
Thank you!
Shy Albatross
sure thing, TIL: it will try to build routes statically if it thinks they are not dynamic "enough" 😄
Little fire antOP
Yeh app router is intresting
I need to learn more about it