Freshでapiフォルダとutilsフォルダの使い分け

作成日
更新日

FreshにはDeno Fresh CRUD API機能がある。

  • apiフォルダ
  • utils もしくは libs と名づけることが多そう?なフォルダ。

例えば getPosts という関数はどちらに配置すべきなのか。

api に配置した場合

これはクライアント側で呼び出される。 例えば、次のようなSupabaseから記事を取得するコードの場合。

api/getPosts.ts
import { Handlers } from "$fresh/server.ts";
import { supabase } from "../../utils/supabase.ts";

interface Post {
  title: string;
  slug: string;
  created_at: string;
}

export const handler: Handlers = {
  async GET(_req, ctx) {
    const { data, error } = await supabase
      .from("articles")
      .select("title, slug, created_at")
      .eq("category", "post")
      .eq("private", false)
      .order("created_at", { ascending: false });

    if (error || !data) return new Response(JSON.stringify([]), { status: 500 });

    return new Response(JSON.stringify(data), {
      headers: { "Content-Type": "application/json" },
    });
  },
};

これはislandから次のように呼び出す。

export default function Sidebar() {
  const [posts, setPosts] = useState<Post[]>({});

  useEffect(() => {
    async function fetchPosts() {
      try {
        const res = await fetch("/api/getPosts");
        const data = await res.json();
        setPosts(data);
      } catch (error) {
        console.error("Failed to fetch posts:", error);
      }
    }

    fetchPosts();
  }, []);
    return (
    <>
    /*postsを表示する*/
    </>
    )
}

これは、useEffectを使ってクライアント側で処理がされる。

utils に配置した場合

サーバー側で呼び出される。

同様にSupabaseから記事を取得するコード。

utils/getPosts.ts
import { supabase } from "./supabase.ts";
import { Post } from "../types/post.ts";

export async function getPosts(): Promise<Post[]> {
  const { data, error } = await supabase
    .from("articles")
    .select("title, slug, created_at")
    .eq("private", false)
    .order("created_at", { ascending: false });

  if (error || !data) {
    console.log(error);
    return [];
  }
  return data;
}

これは通常のコンポーネントから props を通して呼び出す。

index.tsx

interface HomeData {
  posts: Post[];
}
export const handler: Handlers<HomeData> = {
  async GET(_req, ctx) {
    // すべての記事を取得
    const allPosts = await getPosts() ?? [];
    return ctx.render({
      posts: allPosts,
    });
  },
};
export default function Home(props: PageProps<HomeData>) {
  const { posts } = props.data;
  return (
    <>
    /*postsを表示する*/
    </>
  )
}

この方法はSSRになる。

まとめ

  • api に配置した場合は クライアントサイドレンダリング
  • utils に配置した場合はサーバーサイドレンダリング

自分なりの結論として、全ての記事を取得するような時はSSR、画像などを遅延読み込みする時はクライアントサイドの方が良いという認識をした。

サイトアイコン
公開日
更新日