Connect a CKAN backend
Goal: stop reading static files from /public/data/ and instead list and render
datasets straight from a live CKAN instance over its REST API — the
decoupled, "any backend" path.
Before you start
You need a portal scaffolded with
/new-portaland the
root URL of a publicly reachable CKAN instance (e.g.
https://demo.dev.datopian.com). The skill appends/api/3/action/...itself.
The AI path — /connect-ckan
/connect-ckan https://demo.dev.datopian.com
Optionally restrict the catalog to one or more organizations or groups:
/connect-ckan https://demo.dev.datopian.com — orgs: my-org
/connect-ckan verifies the CKAN API is reachable,
installs @portaljs/ckan, generates a lib/ckan.ts client module, and rewrites the
home page and dataset route to fetch from CKAN. It runs a full next build and
reports how many dataset pages were generated.
How it works — the decoupled model
The frontend is independent from the backend and talks to it over the API
(package_search for the catalog, package_show for each dataset). The generated
pages fetch CKAN server-side in getStaticProps/getStaticPaths, so the
@portaljs/ckan bundle never reaches the browser — the client stays lean and the site
can still deploy statically.
It writes plain, editable code:
lib/ckan.ts— a sharedCKANclient. The base URL defaults to what you passed and is overridable at deploy time via theDMSenv var; org/group filters and a build-timeMAX_DATASETScap live here as plain constants.pages/index.tsx— a catalog home that lists datasets frompackage_search.pages/datasets/[slug].tsx— one statically generated page per dataset, with CSV/TSV resources previewed through the template's local<Table />.
Keep CKAN calls server-side
Reference
ckan,DMS, and the filters only inside
getStaticProps/getStaticPaths. If a component body imports them, Next.js bundles
the whole@portaljs/ckanpackage into the client. Pass plain serializable props to
components instead.
The by-hand path
Install the client and create lib/ckan.ts:
npm install @portaljs/ckan@^0.1.0
import { CKAN } from '@portaljs/ckan';
export const ckan = new CKAN((process.env.DMS || 'https://demo.dev.datopian.com').replace(/\/+$/, ''));
Then call ckan.packageSearch(...) from getStaticProps on the home page and
ckan.getDatasetDetails(slug) from a dynamic pages/datasets/[slug].tsx, passing the
results as props.
TypeScript types for @portaljs/ckan
Under the template's
moduleResolution: "bundler", add apathsentry in
tsconfig.jsonso TypeScript finds the declarations:
"@portaljs/ckan": ["./node_modules/@portaljs/ckan/dist/index.d.ts"]. Without it the
build fails to type-check.
Notes
- Data freshness vs. static deploy: the default is SSG — fast and statically
hostable, but data is fixed at build time (rebuild to pick up new datasets). For
always-live data, deploy to a Node host and switch to
getServerSidePropsorgetStaticPathsfallback: 'blocking'. - Build time scales with dataset count: each dataset is one request and one static
page.
MAX_DATASETScaps it on large instances. - CORS for previews: the
<Table>preview fetches resource URLs from the browser; datastore-backed resources are the most reliable.