Hydra and JSON-LD Resources

MAMS 2.0.0 adds an optional Hydra representation to existing resource URLs. A client can discover resource identities, collection members and supported HTTP methods, while application state remains ordinary JSON inside a data field. You can use it with Java-Types resources without changing the agent’s resource goals or passive/active management strategy.

Download the Hydra collection example, extract it and run:

mvn clean compile astra:run

Use Java 17 or later and Maven. Stop other examples using port 9000 first.

Enable the representation

Alongside mams-astra-javatypes:2.4.1, add this dependency to the application serving the resources:

<dependency>
  <groupId>mams-ucd</groupId>
  <artifactId>mams-cartago-hydra</artifactId>
  <version>2.4.1</version>
</dependency>

The module registers its converter through Java’s ServiceLoader. There is no separate ASTRA Hydra library or setup goal. Keep the provider on the runtime classpath; if packaging a shaded JAR, merge META-INF/services using Maven Shade’s ServicesResourceTransformer. The deployment example keeps dependencies as separate JARs.

The agent publishes the same greeting collection as the collection walkthrough:

agent Main extends mams.javatypes.Passive {
    plan +!main(list args) {

        MAMSAgent::!setup();

        MAMSAgent::!created("base");


        Passive::!listResource("hello", "Hello");
     }

}

Read a collection and its members

Ask for JSON-LD explicitly:

curl -i -H 'Accept: application/ld+json' \
  http://localhost:9000/main/hello

The response uses Content-Type: application/ld+json, includes Vary: Accept and supplies a Link header identifying Hydra API documentation. Its complete inline @context defines the vocabulary. The empty collection has member: [], totalItems: 0 and an @type array containing hydra:Collection. The agent entrypoint /main is also a collection, with type mams:Agent, whose members are its attached resources.

Create a greeting using ordinary JSON while requesting a Hydra response:

curl -i -X POST \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/ld+json' \
  -H 'Slug: rem' \
  -d '{"name":"Rem"}' \
  http://localhost:9000/main/hello

Read /main/hello/rem with the same Accept header. The item has an @id, an @type containing mams:Item, and data: {"name":"Rem"}. It also exposes parent, profile and API-documentation addresses and an operation array. Each operation includes a hydra:method, such as GET or PUT. Reading the collection now returns one member with its identity and data, and totalItems: 1.

data is mapped as a JSON literal. Nested objects, arrays and application keys such as @id are preserved as data; the converter does not invent linked-data meanings for Java fields. The representation uses JSON-LD 1.1, Hydra’s core vocabulary and the versioned MAMS namespace urn:mams:hydra:v1:.

Identities use the artifact’s attached URI. In a container or behind a port mapping, that address may differ from the endpoint your client can reach; see resource addresses.

Discover the context and API

Every supported resource offers these GET routes:

curl -H 'Accept: application/ld+json' \
  http://localhost:9000/main/hello/rem/hydra/context

curl -H 'Accept: application/ld+json' \
  http://localhost:9000/main/hello/rem/hydra/api-documentation

The first returns the complete @context. The second returns a hydra:ApiDocumentation document with an entrypoint, a resource-specific class, supported properties and registered operations. These routes return 405 for other methods, 406 for incompatible Accept headers and 404 for unknown paths beneath hydra. Existing /profile routes retain their schema role.

Operations describe methods supported by the artifact, rather than an authorization promise. An active agent may still refuse a listed operation or fail to decide within its timeout. Application policies, such as the delivery service’s read-only child resources, are not inferred from agent plans. Collection counts describe currently attached children; this implementation does not add pagination or search.

Write using the MAMS JSON-LD profile

Plain JSON writes continue to work. To submit application/ld+json, include the exact complete inline context returned by MAMS and one non-null data payload. Copy the context rather than retyping an abbreviated version:

curl -sS -H 'Accept: application/ld+json' \
  http://localhost:9000/main/hello/rem/hydra/context > hydra-context.json

python3 - <<'PY'
import json
with open('hydra-context.json') as source:
    context = json.load(source)['@context']
with open('hydra-update.json', 'w') as target:
    json.dump({'@context': context, 'data': {'name': 'Bob'}}, target)
PY

curl -i -X PUT \
  -H 'Content-Type: application/ld+json' \
  -H 'Accept: application/ld+json' \
  --data-binary @hydra-update.json \
  http://localhost:9000/main/hello/rem

The response’s data now contains {"name":"Bob"}. MAMS unwraps data before Java mapping or JSON Schema validation. POST a single member’s payload to a collection to create it; submitting a collection representation with member does not replace the collection. PUT and PATCH retain the artifact’s existing update semantics; this release does not introduce JSON Patch or JSON Merge Patch.

This is a bounded JSON-LD write profile. Remote contexts, alternate aliases, expanded documents, unknown envelope properties, member and null data are rejected with 400 before mutation. The server does not fetch a submitted context. Read-only identity and hypermedia fields are ignored; the request route selects the resource being modified. Schema validation failures retain 422. Errors retain the usual JSON {error,message} body even when Accept requests JSON-LD.

Compatibility and extensions

Installing Hydra leaves existing JSON and HAL bodies and defaults in place. Typed resources default to JSON when Accept is missing; command-based HAL compatibility reads retain their HAL default. Without the optional provider, requesting application/ld+json returns 406.

The converter supports Java-Types, JSON Schema and the current HAL artifact families, including command-based HAL item/list reads. The separate RDF modules keep their own implementation. Java artifact subclasses can override representationType() to supply an absolute semantic type IRI and representationLinks() to add relationships keyed by absolute property IRIs. Custom resource implementations should report their registered methods through representationMethods().

See the upstream Hydra module guide for the implementation contract. The automated example checks cover discovery, JSON and JSON-LD writes, collection membership, error responses and JSON/HAL compatibility.