rustclan
rustclan
Explore posts from servers
TTCTheo's Typesafe Cult
Created by rustclan on 9/3/2023 in #questions
TRPC error handling
Hey guys. I'm currently looking for some advice in regards to handling errors on my trpc endpoints. My current implementation is as follows:
const TicketOverview = () => {
const [hasRan, setHasRan] = useState(false);
const session = useSession();
const theme = useMantineTheme();
const { guildId } = useRouter().query;

const isFetching = useIsFetching();
const isMutating = useIsMutating();
const isRestoring = useIsRestoring();

const { data: guild, error: guildError } = api.guilds.guild.useQuery(
{
guildId: guildId as string,
},
{ enabled: !!guildId }
);

const { data: guildChannels, error: channelError } =
api.guilds.guildChannels.useQuery(
{
guildId: guildId as string,
},
{ enabled: !!guildId }
);

const { data: guildCategories, error: categoryError } =
api.guilds.guildCategories.useQuery(
{
guildId: guildId as string,
},
{ enabled: !!guildId }
);

// if any of the queries are still in progress...
if (session.status === 'loading' || isFetching || isRestoring || isMutating)
return <Loading />;

if (guildError || channelError || categoryError) {
return (
<div>
{guildError?.message ||
channelError?.message ||
categoryError?.message
}
</div>
);
}

return (
<div>
<h1>Pages content...</h1>
</div>
)
}
const TicketOverview = () => {
const [hasRan, setHasRan] = useState(false);
const session = useSession();
const theme = useMantineTheme();
const { guildId } = useRouter().query;

const isFetching = useIsFetching();
const isMutating = useIsMutating();
const isRestoring = useIsRestoring();

const { data: guild, error: guildError } = api.guilds.guild.useQuery(
{
guildId: guildId as string,
},
{ enabled: !!guildId }
);

const { data: guildChannels, error: channelError } =
api.guilds.guildChannels.useQuery(
{
guildId: guildId as string,
},
{ enabled: !!guildId }
);

const { data: guildCategories, error: categoryError } =
api.guilds.guildCategories.useQuery(
{
guildId: guildId as string,
},
{ enabled: !!guildId }
);

// if any of the queries are still in progress...
if (session.status === 'loading' || isFetching || isRestoring || isMutating)
return <Loading />;

if (guildError || channelError || categoryError) {
return (
<div>
{guildError?.message ||
channelError?.message ||
categoryError?.message
}
</div>
);
}

return (
<div>
<h1>Pages content...</h1>
</div>
)
}
This is a quick example showing what i would like to display when an error occurs, but it doesn't feel very nice... is there any alternatives?
4 replies
TTCTheo's Typesafe Cult
Created by rustclan on 4/30/2023 in #questions
TRPC ratelimiting endpoints (race conditions)
I am currently having some problems with a race condition in my TRPC nextJS api. Essentially what is happening is I have a enforceGuildPermissions method, which basically checks if the user who is making the request has permission to get the data for that guild. The data is stored in my Redis cache for 3 seconds. This works okay sometimes, but other times because there is 3-4 different trpc requests running for a single page which are guild, role and channel. It causes the last request (channel) to get rate limited by the discord API because they are all running concurrently, this means it doesn't give my caching code chance to update it before the next one runs. middleware route procedure:
const enforceGuildPermissions = enforceUserLoggedIn.unstable_pipe(
async ({ ctx, next, rawInput }) => {
const guildId: unknown = (rawInput as { guildId?: unknown })?.guildId;
if (!guildId) throw new TRPCError({ code: 'BAD_REQUEST' });

const webUser = await cache.webUsers.get(ctx.session.user.id);
let guilds = webUser?.guilds;
if (!guilds) {
guilds = await getUserGuilds(ctx.session)
}

if (!guilds) throw new TRPCError({ code: 'UNAUTHORIZED' });

// if the user is not in the guild return unauth
const foundGuild = guilds.find((guild) => guild.id === guildId);
if (!foundGuild) throw new TRPCError({ code: 'UNAUTHORIZED' });

return next({
ctx: {
session: { ...ctx.session, user: ctx.session.user },
},
});
}
);

export const guildProcedure = t.procedure.use(enforceGuildPermissions);
const enforceGuildPermissions = enforceUserLoggedIn.unstable_pipe(
async ({ ctx, next, rawInput }) => {
const guildId: unknown = (rawInput as { guildId?: unknown })?.guildId;
if (!guildId) throw new TRPCError({ code: 'BAD_REQUEST' });

const webUser = await cache.webUsers.get(ctx.session.user.id);
let guilds = webUser?.guilds;
if (!guilds) {
guilds = await getUserGuilds(ctx.session)
}

if (!guilds) throw new TRPCError({ code: 'UNAUTHORIZED' });

// if the user is not in the guild return unauth
const foundGuild = guilds.find((guild) => guild.id === guildId);
if (!foundGuild) throw new TRPCError({ code: 'UNAUTHORIZED' });

return next({
ctx: {
session: { ...ctx.session, user: ctx.session.user },
},
});
}
);

export const guildProcedure = t.procedure.use(enforceGuildPermissions);
3 replies
TTCTheo's Typesafe Cult
Created by rustclan on 12/4/2022 in #questions
TRPC cache (with vercel, but not working locally too)
Hello. I am using TRPC to make a site which integrates with a third party API. I need to add caching to some of my routes. I have tried to implement a temporary global cache, as seen below. In order to stop rate limits for the third party api.
// export API handler
export default createNextApiHandler({
router: appRouter,
createContext,
responseMeta({ ctx, paths, type, errors }) {
// checking that no procedures errored
const allOk = errors.length === 0;
// checking we're doing a query request
const isQuery = type === "query";
console.log(1);
if (ctx && allOk && isQuery) {
console.log(2);
// cache request for 1 day + revalidate once every second
const ONE_DAY_IN_SECONDS = 15000;
return {
headers: {
"cache-control": `s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`,
},
};
}
return {};
},
});
// export API handler
export default createNextApiHandler({
router: appRouter,
createContext,
responseMeta({ ctx, paths, type, errors }) {
// checking that no procedures errored
const allOk = errors.length === 0;
// checking we're doing a query request
const isQuery = type === "query";
console.log(1);
if (ctx && allOk && isQuery) {
console.log(2);
// cache request for 1 day + revalidate once every second
const ONE_DAY_IN_SECONDS = 15000;
return {
headers: {
"cache-control": `s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`,
},
};
}
return {};
},
});
However, the cache-control header does not get changed, and nothing is cached. Mutiple requests are still made to the third party API. The cache code does run, as the console.log(2) appears in console. Any clue whats wrong?
2 replies
TTCTheo's Typesafe Cult
Created by rustclan on 11/30/2022 in #questions
TRPC max retries on endpoint
15 replies
TTCTheo's Typesafe Cult
Created by rustclan on 11/20/2022 in #questions
invalid environment variables
27 replies
TTCTheo's Typesafe Cult
Created by rustclan on 10/7/2022 in #questions
Nextjs hostname is not configured under images in next.config.js
Hey I am getting the following error when trying to display a discord image on my website through their cdn
on `next/image`, hostname "cdn.discordapp.com" is not configured under images in your `next.config.js`
on `next/image`, hostname "cdn.discordapp.com" is not configured under images in your `next.config.js`
I have added the domains into the defineNextConfig inside of next.config.mjs but I still get the same error.
// @ts-check
import { env } from "./src/env/server.mjs";

/**
* Don't be scared of the generics here.
* All they do is to give us autocompletion when using this.
*
* @template {import('next').NextConfig} T
* @param {T} config - A generic parameter that flows through to the return type
* @constraint {{import('next').NextConfig}}
*/
function defineNextConfig(config) {
return config;
}

export default defineNextConfig({
reactStrictMode: true,
swcMinify: true,
// Next.js i18n docs: https://nextjs.org/docs/advanced-features/i18n-routing
i18n: {
locales: ["en"],
defaultLocale: "en",
},
images: {
domains: ["avatars.githubusercontent.com", "cdn.discordapp.com", "lh3.googleusercontent.com"],
},
});
// @ts-check
import { env } from "./src/env/server.mjs";

/**
* Don't be scared of the generics here.
* All they do is to give us autocompletion when using this.
*
* @template {import('next').NextConfig} T
* @param {T} config - A generic parameter that flows through to the return type
* @constraint {{import('next').NextConfig}}
*/
function defineNextConfig(config) {
return config;
}

export default defineNextConfig({
reactStrictMode: true,
swcMinify: true,
// Next.js i18n docs: https://nextjs.org/docs/advanced-features/i18n-routing
i18n: {
locales: ["en"],
defaultLocale: "en",
},
images: {
domains: ["avatars.githubusercontent.com", "cdn.discordapp.com", "lh3.googleusercontent.com"],
},
});
Any clue what's wrong?
7 replies