@iplweb/radon-opendata
v0.1.1
Published
Zero-dependency, framework-agnostic browser/Node client for the Polish RAD-on OpenData API (radon.nauka.gov.pl) — look up scientists, projects, patents and artistic achievements, with ORCID-based verification.
Maintainers
Readme
@iplweb/radon-opendata
Zero-dependency, framework-agnostic client for the Polish RAD-on OpenData API (radon.nauka.gov.pl) — look up a scientist by name and pull their academic degrees, titles, employment, research projects, patents and artistic achievements, keyed and verified by ORCID.
Works in the browser (RAD-on serves permissive CORS on these endpoints) and in Node ≥ 18. Ships ESM + CJS + type declarations. No runtime dependencies.
Why
RAD-on's public OpenData API is searchable by name, not by ORCID — but the
records it returns carry the person's ORCID. This library turns that into
reliable matching: search by surname, then keep only the records whose ORCID
equals the one you already hold. Two Jan Kowalskis stop being a problem.
Data comes from these live, CORS-open endpoints (verified 2026-07-07):
| Dataset | Endpoint | Person filter | ORCID field used to verify |
| ------------------------------ | --------------------------------- | ---------------------- | ------------------------------------ |
| CV (degrees/titles/employment) | POST /scientist/search | firstName/lastName | personalData.orcid |
| Research projects | GET /polon/projects | project manager name | projectManagers[].ORCID |
| Patents / protection rights | GET /polon/products | inventor name | inventors[].persons[].relatedOrcid |
| Artistic achievements | GET /polon/artisticAchievements | author name | authors[].orcid |
Publications are intentionally not included — RAD-on can serve them (
GET /polon/publications?orcidId=…), but most bibliography systems already hold their own. Add that endpoint yourself if you need it.
Install
npm install @iplweb/radon-opendataQuick start
One call does search → ORCID-verify → normalize for every dataset in parallel, degrading gracefully if any single endpoint is down:
import {
createRadonClient,
fetchAchievementsByOrcid,
} from "@iplweb/radon-opendata";
const client = createRadonClient(); // defaults to https://radon.nauka.gov.pl/opendata
const result = await fetchAchievementsByOrcid(
client,
{
firstName: "Przemysław",
lastName: "Kowalczewski",
orcid: "0000-0002-0153-4624",
},
{ onError: (endpoint, err) => console.debug("[radon]", endpoint, err) },
);
if (result.hasAny) {
console.log(result.cv?.degrees); // [{ name: "Doktor", year: "2016", institution: "…" }, …]
console.log(result.projects); // [{ title, competition, funds, startDate, endDate, … }]
console.log(result.patents); // [{ title, type, publicationNumber, … }]
console.log(result.artisticAchievements);
}fetchAchievementsByOrcid never rejects on a single endpoint failure: the
failing dataset comes back empty and onError is called; the rest still load.
Browser usage
The RAD-on endpoints reflect the request Origin, so you can call them directly
from a page — no proxy, no key, no login:
<script type="module">
import {
createRadonClient,
fetchAchievementsByOrcid,
} from "https://esm.sh/@iplweb/radon-opendata";
const el = document.querySelector("#radon");
const result = await fetchAchievementsByOrcid(createRadonClient(), {
firstName: el.dataset.firstName,
lastName: el.dataset.lastName,
orcid: el.dataset.orcid,
});
// …render result.cv / result.projects / … (use textContent, not innerHTML)
</script>Low-level API
Prefer to drive it yourself? Every piece is exported and independently usable.
import {
createRadonClient,
pickScientistByOrcid,
filterProjectsByOrcid,
extractScientistCv,
extractProject,
orcidMatches,
} from "@iplweb/radon-opendata";
const client = createRadonClient({
// baseUrl: "https://your-proxy.example/rad", // e.g. a same-origin proxy
// fetch: customFetch, // inject fetch (tests, Node < 18)
});
const scientists = await client.searchScientist({ lastName: "Kowalczewski" });
const me = pickScientistByOrcid(scientists, "0000-0002-0153-4624");
const cv = me ? extractScientistCv(me) : null;
const projects = filterProjectsByOrcid(
await client.fetchProjects({ lastName: "Kowalczewski" }),
"0000-0002-0153-4624",
).map(extractProject);Exports
- Client:
createRadonClient(options?)→{ searchScientist, fetchProjects, fetchPatents, fetchArtisticAchievements }. Options:baseUrl,fetch. - ORCID:
normalizeOrcid(value),orcidMatches(a, b). - Selectors:
pickScientistByOrcid,filterProjectsByOrcid,filterPatentsByOrcid,filterAchievementsByOrcid. - Extractors:
extractScientistCv,extractProject,extractPatent,extractArtisticAchievement. - Aggregate:
fetchAchievementsByOrcid(client, query, options?). - Types: all API and result shapes are exported.
Matching rules & caveats
- Verification is by ORCID. CV, projects and artistic achievements are returned only when the embedded ORCID matches — no fuzzy name guessing.
- Patents may lack ORCID in POL-on.
filterPatentsByOrciddrops unverifiable patents by design; loosen it in your own code if you accept name-only matching. - No caching / persistence. Calls hit RAD-on live. Cache upstream if needed.
- Best-effort data. RAD-on may change field shapes; unknown/missing fields
normalize to
null/[]rather than throwing.
Development
npm install
npm test # vitest
npm run typecheck
npm run build # tsup → dist (ESM + CJS + d.ts)License
MIT © IPLWeb. Not affiliated with OPI PIB / the RAD-on system; consumes public open data.
