LoginSignup
0
0

More than 1 year has passed since last update.

sveltekitの.json.tsファイルでinterfaceで定義されたオブジェクトを返す

Posted at

sveltekitでは,routeディレクトリ内の.json.tsファイルでサーバーでの処理を記述でき,そこからjsonレスポンスを取得することができます.getメソッドの定義ではjsonに変換できるオブジェクトならなんでもbodyとして返すことができます.
今回は,その返り値にinterfaceを定義したオブジェクトを利用するときに少しハマったのでメモしておきます.

以下のように[slug].json.tsでマークダウンファイルを読み込み,ページのメタ情報とhtmlの文字列を返すgetメソッドを定義したいとします.

[slug].json.ts
import type { RequestHandler } from '@sveltejs/kit';
import fs from "fs"
import {mdToHtml} from '$lib/convert_markdown';
import type {HtmlWithMeta} from '$lib/convert_markdown';

const ARTICLES_DIR_PATH = "contents/articles";  // 記事のあるディレクトリのパス

export const get: RequestHandler = async ({params}) => {
    const md_str = fs.readFileSync(ARTICLES_DIR_PATH + "/" + params.slug + ".md").toString();
    const html_with_meta: HtmlWithMeta = mdToHtml(md_str);
    return {body: html_with_meta}
}

ここで,mdToHtmlはマークダウンの文字列をHtmlWithMetaインターフェースのオブジェクトに変換する関数です.インターフェースは以下のように定義されているとします.

convert_markdown.ts
/** メタ情報を含んだhtmlの情報 */
interface HtmlWithMeta {
    content: string,  // htmlの文字列
    meta_property: MetaProperty,  // 記事のメタ情報
    use_katex: boolean,  // 数式を使うかどうか
    use_code: boolean  // コードを使うかどうか
}

/** ページのメタ情報 */
interface MetaProperty {
    title: string,  // ページのタイトル
    page_path: string,  // ページの相対パス
    page_desc: string,  // ページの概要
    og_image_url: string  // OGP 画像のurl・パス
}

しかし上のget関数はコンパイルが通りません.これはHtmlWithMetaインターフェースが公式ドキュメントで定義されている型に変換できないためだと思われます.そこで以下のように一度JSONを通すことでコンパイルが通るようになります.

[slug].json.ts
return {body: JSON.parse(JSON.stringify(html_with_meta))}

スプレッド構文を利用することもできますがHtmlWithMetaのようにインターフェースがネストしている場合は,以下のようにネストしている部分を後からスプレッド構文で置き換える必要があります.

[slug].json.ts
return {
    body:{
        ...html_with_meta,
        meta_property:{...html_with_meta.meta_property},
    }
}

クライアント側の[slug].svelteでは通常と同じように利用できます.

[slug].svelte
<script context="module" lang="ts">
    import type { Load } from '@sveltejs/kit'
    import type {HtmlWithMeta} from "$lib/convert_markdown";

    const ARTICLE_URL = "/articles"
    export const load: Load = async({page, fetch}) => {
        const html_with_meta_res = await fetch(ARTICLE_URL + "/" + page.params.slug + ".json");
        if (html_with_meta_res.ok) {
            let html_with_meta: HtmlWithMeta = await html_with_meta_res.json();
            return {props: {html_with_meta}}
        }
    };
</script>

<script lang="ts">
    export let html_with_meta: HtmlWithMeta;
</script>
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0