Manage resources and their state

The first service exposed one greeting. Now decide how a client identifies data, how new data enters the service, and who publishes changes. These decisions form the resource contract. This chapter uses MAMS 2.4.1 and ASTRA 2.6.1.

Choose an item or a collection

An individual item has a name chosen when the agent creates it, such as /main/hello. A collection represents a growing set of items: POST creates a child, GET reads it, PUT changes it and DELETE removes it. Use an item for a known entity or current service state; use a collection when clients submit new entities or requests.

Download the passive collection project. It uses the same Hello data class as chapter 1, but creates a collection:

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

        MAMSAgent::!setup();

        MAMSAgent::!created("base");


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

}

Stop the previous Hello service, extract this project and run mvn clean compile astra:run. In another terminal, create a greeting:

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

Expect 201 Created and a Location header. That header identifies the created resource; the requested slug is a suggestion rather than a substitute for reading the response. For this local example its path is /main/hello/ada. Read it, then remove it:

curl -i -H 'Accept: application/json' http://localhost:9000/main/hello/ada
curl -i -X DELETE http://localhost:9000/main/hello/ada
curl -i http://localhost:9000/main/hello/ada

The last GET should return 404. A second POST with an already-used slug returns 409 Conflict. The collection walkthrough explains the complete representation and lifecycle.

Separate a Java value from stored state

The resource’s artifact holds the published state. get(Value) reconstructs a Java object; changing that object does not itself change the resource. Call replace(Value) to publish the revised state and emit its replacement notification.

Step

Where the state lives

Client sends JSON

The HTTP request body

Resource processes the write

Observable properties on the artifact

Agent calls get

A reconstructed Java object

Agent modifies that object

The local Java value

Agent calls replace

Updated artifact properties, visible to clients

Use the artifact(Name, QualifiedName, Id) mapping to locate the artifact. For directly created items, the logical name and qualified artifact name differ. Discovered collection children are recorded with their qualified name. Working with resources gives both patterns.

Changing a property directly is also different from replacing an object: it does not automatically emit the same replaced signal. Choose the operation that matches the notification contract you need. Avoid treating an HTTP response as proof that every resulting agent plan has finished.

Decide who owns each field

A greeting lets a client write name. A delivery request needs a different contract: the client supplies orderId and destination, while the agent owns status and courier. Record that ownership before implementing write permissions.

Java-Types reflection is convenient for simple data. Its replacement operation skips null field values, so do not assume JSON null clears a nullable field. Test omitted values, nulls and primitive defaults for your chosen data class. For stronger validation, consider the schema-based implementation rather than assuming the Java class expresses every business constraint.

Create a custom artifact directly

Use mams.MAMSAgent::!createResource(...) when a Java-Types item does not express the behaviour you need. The goal connects a custom ResourceArtifact to a parent resource, installs its route, focuses the agent and records its identity. You supply the artifact’s initialization arguments and HTTP handler.

The custom counter walkthrough publishes an agent-owned value at /main/counter without a Java-Types data class. This is also the foundation of the custom topic in the WebSub example. A custom artifact owns its method support and response contract; inheriting ResourceArtifact does not automatically provide collection semantics or active request decisions.

Choose a representation

Begin with JSON so the contract is easy to inspect. HAL adds links that clients can follow; the optional Hydra provider adds JSON-LD identities and discovery. These describe access to existing resources rather than completing an agent’s business task.

Accept selects a supported response format; Content-Type describes a submitted body. Keep client code independent of a guessed collection JSON shape. Use returned links and Location, and check errors before parsing a success representation.

Try it

Create two greetings, rename one with PUT, delete the other and inspect the collection after each operation. Repeat a slug to observe 409. Explain which changes cause an agent notification and which merely read state.

Next: Decide how requests are handled.

Further Details