Guides

Resources

Explain resource definitions, action paths, and the model behind route-aware controllers.

Resource context is the shared model behind route-aware controllers and resource path helpers.

It tells Ginjou what each resource is called, which paths belong to each action, and which defaults should be reused for that resource.

Router context is only needed when Ginjou must read or write the current location, such as resource inference or controller route sync.

Controller or helperHow it uses resource data
useCreateResolve the resource name and default fetcher for create flows.
useEditResolve the resource name, default id, and default fetcher for edit flows.
useShowResolve the resource name, default id, and default fetcher for detail pages.
useListResolve the resource name and default fetcher for list pages.
useInfiniteListResolve the resource name and default fetcher for infinite lists.
useSelectResolve the resource name and default fetcher for select data.
useResourceResolve the current resource from an explicit name or from the current location.
useResourcePathBuild action paths from the resource definition.

Resource Context

Resource context is the registry of resource definitions for your app.

Each definition names one resource, declares its action paths, and can attach resource-level metadata.

Interface

interface Resource {
    resources: Array<{
        name: string
        list?:
            | string
            | {
                pattern: string
                parse: (location: any) => any
            }
        create?:
            | string
            | {
                pattern: string
                parse: (location: any) => any
            }
        show?:
            | string
            | {
                pattern: string
                parse: (location: any) => any
            }
        edit?:
            | string
            | {
                pattern: string
                parse: (location: any) => any
            }
        meta?: {
            parent?: string
            hide?: boolean
            deletable?: boolean
            fetcherName?: string
            [key: string]: any
        }
    }>
}

Properties

PropertyMeaning
resourcesThe full list of resource definitions.

Resource Item

PropertyMeaning
nameThe stable identifier for one resource.
listThe route definition for list pages.
createThe route definition for create pages.
showThe route definition for detail pages.
editThe route definition for edit pages.
metaExtra resource-level settings and metadata.

Meta

PropertyMeaning
parentOptional parent resource name.
hideOptional UI hint to hide a resource.
deletableOptional flag for delete support.
fetcherNameThe default fetcher used when a composable does not pass its own fetcherName.
<script setup lang="ts">
import { defineResource } from '@ginjou/core'
import { defineResourceContext } from '@ginjou/vue'

defineResourceContext(defineResource({
    resources: [
        {
            name: 'posts',
            list: '/posts',
            create: '/posts/create',
            show: '/posts/:id',
            edit: '/posts/:id/edit',
        },
    ],
}))
</script>

Name and Action Paths

name is the stable resource identifier used by higher-level composables. Action paths such as list, create, show, and edit tell Ginjou how to match or build URLs for that resource.

String patterns are enough for standard CRUD pages. When router context exists, route-aware controllers compare the current location against the registered action paths.

With the posts definition above, useShow() can infer the current resource and record id without passing either one explicitly.

<script setup lang="ts">
import { useShow } from '@ginjou/vue'

const post = useShow()
</script>

If the current route is /posts/42, useShow() resolves the posts resource, the show action, and the current id.

Current routeResolved resourceResolved actionResolved id
/postspostslist-
/posts/createpostscreate-
/posts/42postsshow42
/posts/42/editpostsedit42

Fetcher Selection

Each resource can define meta.fetcherName as its default fetcher.

Controllers such as useList, useShow, useCreate, useEdit, and useSelect read that value automatically.

Fetcher selection follows this order.

PrioritySourceUsed when
1fetcherName passed directly to a composableAlways wins.
2resource.meta.fetcherNameUsed when the composable does not pass fetcherName.

This lets you set one backend per resource without repeating it in every composable call.

Register the resource with a default fetcher.

<script setup lang="ts">
import { defineResource } from '@ginjou/core'
import { defineResourceContext } from '@ginjou/vue'

defineResourceContext(defineResource({
    resources: [
        {
            name: 'posts',
            list: '/posts',
            show: '/posts/:id',
            meta: {
                fetcherName: 'cms',
            },
        },
    ],
}))
</script>

Then consume it from a controller. Passing fetcherName locally still overrides the resource default.

<script setup lang="ts">
import { useList, useShow } from '@ginjou/vue'

const posts = useList({
    resource: 'posts',
})

const preview = useShow({
    resource: 'posts',
    id: 1,
    fetcherName: 'preview',
})
</script>

In that example, useList() uses cms, while useShow() uses preview because the local prop has higher priority.

Custom Parsing

Each action path can also use an object with pattern and parse.

Use this when plain path matching is not enough and the current route needs custom interpretation.

FieldUsed for
patternDefines the path shape and is still used for path creation.
parseAdds custom route inference when pathname matching alone is not enough.
import { defineResource, ResourceActionType } from '@ginjou/core'

defineResource({
    resources: [
        {
            name: 'posts',
            show: {
                pattern: '/posts/:id',
                parse(location) {
                    if (location.query?.mode !== 'detail')
                        return

                    const matched = /^\/posts\/([^/]+)$/.exec(location.path)
                    if (!matched)
                        return

                    return {
                        action: ResourceActionType.Show,
                        id: matched[1],
                    }
                },
            },
        },
    ],
})

That lets route inference depend on more than the pathname.

Path creation still uses /posts/:id, because path creation reads pattern, not parse.

Current Resource

useResource() resolves one resource definition and its parsed route state.

When you pass name, Ginjou resolves that resource directly. If router context also exists, it still parses the current location against that resource. When you omit name, Ginjou checks the registered resources in order and returns the first one that matches the current location.

FieldMeaning
resourceThe matched resource definition.
actionThe matched action such as list, show, or edit.
idThe parsed record id when the route includes one.

If resource context is missing, or no definition matches, the result is undefined.

<script setup lang="ts">
import { useResource } from '@ginjou/vue'

const inferred = useResource()
const posts = useResource({
    name: 'posts',
})
</script>

<template>
    <div>
        <p>Current resource: {{ inferred?.resource.name }}</p>
        <p>Current action: {{ inferred?.action }}</p>
        <p>Current id: {{ inferred?.id }}</p>
        <p>Explicit resource: {{ posts?.resource.name }}</p>
    </div>
</template>

This is the lower-level primitive behind route-aware controllers such as useShow() and useEdit().

Build Resource Paths

useResourcePath() builds one action path from the resolved resource definition.

You can pass a resource name explicitly, or let Ginjou start from the current resolved resource.

InputEffect
actionPicks the target action path such as list, create, show, or edit.
resourceResolves that resource instead of using the current one.
paramsFills route params such as :id and overrides inferred values when both exist.

When the current resource already includes an id, path creation can reuse it.

<script setup lang="ts">
import { ResourceActionType } from '@ginjou/core'
import { useResourcePath } from '@ginjou/vue'

const createPath = useResourcePath({
    action: ResourceActionType.Create,
    resource: 'posts',
})

const editPath = useResourcePath({
    action: ResourceActionType.Edit,
    resource: 'posts',
    params: {
        id: 42,
    },
})
</script>
VariableResult
createPath/posts/create
editPath/posts/42/edit

If the resource cannot be resolved, or the target action path is missing, the result is undefined.

This keeps links aligned with the same resource definitions that power your controllers.

Copyright © 2026