Publishing datasets
The control plane owns public dataset metadata and private backend configuration. The HTTP data plane executes transfers using the configuration it receives when a dataflow is prepared.
Publish through Dataspace Starter
Enable the application alongside your HTTP data plane:
components:
controlPlane:
enabled: true
dataPlanes:
http-data-plane: {}
useCaseApps:
dataspace-starter: {}
In the single-participant example, open https://alfa.example.com/dataspace-starter/.
The CLI supplies the service connections. Select a participant tenant and sign in.
- Open Datasets and choose New dataset.
- Select the registered HTTP data plane. If none is listed, check its logs and its registration in the control plane before publishing.
- Enter a title, description and keywords.
- Enter the backend URL reachable from the HTTP data plane and, if needed, the
complete authorization header, such as
Bearer <backend-api-key>. - Optionally enter a public OpenAPI URL and generate metadata from it. Starter fetches public specifications through its authenticated server endpoint. Private network URLs are rejected, responses are limited to 2 MiB, and each HTTP request has a ten-second timeout. Backend access itself can still use private network addresses reachable by the data plane.
- Set an ODRL policy if the default offer does not express your requirements.
- Publish, then check Own Catalog. Use a second participant's Tester to negotiate and request data from the provider.
The backend URL and authorization belong in private configuration. Do not copy credentials or internal backend addresses into public DCAT distributions. An OpenAPI document is public metadata, so it must not contain secrets either.
Automate publication through the control plane
The tenant-scoped management endpoint is POST /api/management/datasets.
Send Authorization: Bearer <token> and X-Tenant-Slug: <participant-slug>.
The SDK handles these headers:
import { defaultContext } from "@tsg-dsp/common-dsp";
import { TsgSdk } from "@tsg-dsp/tsg-sdk";
const sdk = TsgSdk.create({
controlPlaneBaseUrl: "https://alfa.example.com/control-plane/api",
tenantSlug: "alfa",
auth: { method: "access_token", accessToken: process.env.TSG_ACCESS_TOKEN! }
});
const planes = await sdk.catalog.getDataplanes();
// Select the intended registered plane; do not assume its generated id.
const dataPlaneId = process.env.TSG_DATA_PLANE_ID!;
if (!planes.some((plane) => plane.id === dataPlaneId)) {
throw new Error("The selected data plane is not registered in this tenant");
}
await sdk.metadata.publishDataset({
dataPlaneId,
dataset: {
"@context": defaultContext(),
"@type": "Dataset",
"@id": "urn:example:alfa:reference-data",
title: "Alfa reference data",
distribution: [{
"@type": "Distribution",
format: "tsg:HTTP",
conformsTo: ["https://api.example.com/openapi.json"]
}]
},
assetConfig: {
backendUrl: "http://reference-api:8080/data",
authorization: process.env.BACKEND_AUTHORIZATION
}
});
Use the SDK or the management API for repeatable dataset initialization. CLI
render and deploy manage infrastructure; they do not submit dataset records.
Edit metadata and replace credentials
Starter preserves the owning data plane, private backend configuration and
credential requirements during an ordinary metadata edit. The SDK equivalent is
sdk.metadata.updateDatasetMetadata(id, dataset), backed by
PUT /api/management/catalog/dataset/:id. Supply the complete public metadata.
To change a backend URL or rotate a key in Starter, enable Replace backend
configuration for new transfers. Enter the complete new configuration. Leaving
authorization empty removes the existing header. SDK integrations can use
sdk.metadata.updateDataset(id, submission), which replaces private configuration;
omitting assetConfig there clears it. Preserve requirementSetRef explicitly
when using this full replacement endpoint.
Existing HTTP dataflows retain their prepare-time URL and credentials. Neither metadata edits nor explicit backend replacement updates them. For key rotation, keep the old key valid until existing transfers finish, or terminate those transfers and arrange new ones before revoking it. Live credential propagation is not implemented.
Vocabulary hub integration
A vocabulary hub such as Semantic Treehouse
publishes shared data models and their versions. Link to the model your data
follows so consumers can understand its meaning, and link to a schema or OpenAPI
document so they can implement a client. Use the identifiers published by your
community's hub; the vocabulary-hub.example.org URLs below are placeholders.
Put these references directly in the public DCAT metadata. conformsTo is the
TSG JSON-LD context's short name for dct:conformsTo. It accepts multiple IRIs.
The connector advertises these references; it does not fetch a model from the hub,
transform the data to match it, or validate the backend response against it.
Use dataset-level conformsTo for semantic models and application profiles.
Use distribution-level conformsTo for technical schemas and OpenAPI documents.
Both fields can contain multiple references.
Version-specific model references
Publish a base dataset and a separate dataset for each version. The base links
to its versions through hasVersion and hasCurrentVersion; each version has
version and isVersionOf. Add previousVersion when publishing a successor.
These are DCAT properties, independent of how versions are numbered in the hub.
Using sdk, dataPlaneId and defaultContext from the publication example above:
const baseId = "urn:example:patient-demographics";
const versionId = `${baseId}:2.1.0`;
await sdk.metadata.publishDataset({
dataPlaneId,
dataset: {
"@context": defaultContext(),
"@type": "Dataset",
"@id": baseId,
title: "Patient demographics",
conformsTo: ["https://vocabulary-hub.example.org/ontology/demographics"],
hasVersion: [versionId],
hasCurrentVersion: versionId
}
});
await sdk.metadata.publishDataset({
dataPlaneId,
dataset: {
"@context": defaultContext(),
"@type": "Dataset",
"@id": versionId,
title: "Patient demographics 2.1.0",
version: "2.1.0",
isVersionOf: baseId,
conformsTo: [
"https://vocabulary-hub.example.org/ontology/demographics/version/2.1.0"
],
distribution: [{
"@type": "Distribution",
format: "tsg:HTTP",
mediaType: "iana:application/json",
conformsTo: [
"https://vocabulary-hub.example.org/schemas/demographics/2.1.0.json",
"https://api.example.org/patients/openapi.json"
]
}]
},
assetConfig: {
backendUrl: "http://patient-api:8080/v2.1/patients",
authorization: process.env.BACKEND_AUTHORIZATION
}
});
The base is a metadata-only entry with no assetConfig; the version is
transferable. Publish the model reference on every version explicitly, using the
base reference if the hub does not publish a version-specific one. The management
API does not infer it from isVersionOf.
Custom DCAT properties and application profiles
Include domain properties directly in the submitted dataset, alongside title
and distribution. Do not wrap them in an extraProps field in the JSON-LD
request. The SDK also accepts a Dataset class instance; its constructor's
extraProps option is an internal way to produce these same top-level properties
when serialized.
defaultContext() supplies the DSP, TSG and health contexts, including dct,
dcat, xsd, iana and healthdcatap. For other vocabularies, use full IRIs for
property names and types, or supply a matching JSON-LD context. A conformsTo
reference does not load a vocabulary's context. Unmapped JSON-LD terms can lose
meaning during expansion or compaction.
The following examples show how to publish geospatial and health metadata. For application-profile conformance, include all required metadata and validate against the profile version your community uses.
GeoDCAT-AP example
For GeoDCAT-AP, identify geographic coverage
with a location IRI. TSG's current dataset model accepts a string IRI for
dct:spatial, not an embedded location object. The example uses the Netherlands
country identifier. For a custom area, publish a location resource with its
geometry and reference its IRI here; do not put a bare WKT polygon in this field.
await sdk.metadata.publishDataset({
dataPlaneId,
dataset: {
"@context": defaultContext(),
"@type": "Dataset",
"@id": "urn:example:geo-roads:1.0.0",
title: "National road infrastructure",
version: "1.0.0",
conformsTo: ["https://semiceu.github.io/GeoDCAT-AP/"],
"dct:spatial": { "@id": "http://publications.europa.eu/resource/authority/country/NLD" },
"dcat:spatialResolutionInMeters": { "@value": "10.0", "@type": "xsd:decimal" },
"dcat:temporalResolution": { "@value": "P1D", "@type": "xsd:duration" },
distribution: [{
"@type": "Distribution",
format: "tsg:HTTP",
mediaType: "iana:application/geo+json",
conformsTo: ["https://api.example.org/geo/openapi.json"]
}]
},
assetConfig: { backendUrl: "http://geo-api:8080/roads" }
});
HealthDCAT-AP example
For HealthDCAT-AP, the
record count, age range and population coverage belong in the public dataset.
The vocabulary hub's clinical-trial model can be listed alongside the profile.
This example uses the healthdcatap terms from TSG's bundled health context,
which maps that prefix to https://healthdcat-ap.github.io/#. Check the
namespace and profile version agreed in your dataspace when exchanging metadata
with other implementations.
await sdk.metadata.publishDataset({
dataPlaneId,
dataset: {
"@context": defaultContext(),
"@type": "Dataset",
"@id": "urn:example:clinical-trials:2.0.0",
title: "Clinical trial registry",
version: "2.0.0",
conformsTo: [
"https://healthdataeu.pages.code.europa.eu/healthdcat-ap/",
"https://vocabulary-hub.example.org/ontology/clinical-trial/version/2.0.0"
],
"healthdcatap:numberOfRecords": 50000,
"healthdcatap:minTypicalAge": 18,
"healthdcatap:maxTypicalAge": 90,
"healthdcatap:populationCoverage": "National",
distribution: [{
"@type": "Distribution",
format: "tsg:HTTP",
mediaType: "iana:application/json",
conformsTo: ["https://api.example.org/health/openapi.json"]
}]
},
assetConfig: {
backendUrl: "http://clinical-trial-api:8080/trials",
authorization: process.env.BACKEND_AUTHORIZATION
}
});
Shared properties across versions or collection items
Build each version or collection item with its complete public metadata. In the
publishing application, spread shared properties onto each dataset, then apply
version-specific or item-specific values. For example, set
dcat:spatialResolutionInMeters to 25.0 for one version and 10.0 for another,
using the typed decimal values shown above.
Publish the resulting properties on every dataset. Version and collection links describe relationships; they do not cause metadata inheritance.
See DCAT structure for the distinction between dataset semantics, distribution schemas and transfer access services.