Populate model properties via HATEOAS links?

I’ve got a HATEOAS rest api which is returning data like:

{
    "_links": {
        "build": {
            "href": "http://localhost:8080/vulcan-service/v1/deploys/1/build"
        },
        "deploy": {
            "href": "http://localhost:8080/vulcan-service/v1/deploys/1"
        },
        "previousBuild": {
            "href": "http://localhost:8080/vulcan-service/v1/deploys/1/previousBuild"
        },
        "self": {
            "href": "http://localhost:8080/vulcan-service/v1/deploys/1"
        },
        "stack": {
            "href": "http://localhost:8080/vulcan-service/v1/deploys/1/stack"
        }
    },
    "deployTaskDef": null,
    "endedAt": 1510003796000,
    "log": null,
    "startedAt": 1510003696000,
    "startedBy": "jsteel",
    "successful": true
}

I’d like to define the deploy model such that it pulls in the stack property if present, by invoking GET /vulcan-service/v1/deploys/1/stack. This will return a 404 if the property is ‘null’.

Am I going down the wrong path by looking at somehow using Stack.Ref.type here? It’s not quite the same as it doesn’t exist in the main object, but I could perhaps shoehorn it in via can-connect::parseInstanceData() ?

e.g.

const Deploy = DefineMap.extend({
  seal: false
}, {
  id: 'any',
  stack: { type: Stack.Ref.type }
});

Ref wasn’t built for this exact use case (although it is designed for a very similar one). I’ll thibk about it and try to give you some ideas tomorrow.

@Jared_Stehler How far did you get trying this? I think it “could” work if you cleaned up the response (via parseInstanceData) to look more like:

stack: "http://localhost:8080/vulcan-service/v1/deploys/1/stack"

.Ref expects the value at stack to either be an object w/ all data, or the unique ID. It CANT tell the difference between an object and another object that just has the ID.

Once you have that, you should be able to use the Stack.Ref type as you showed and make sure the Stack type is connected like:

Stack = DefineMap.extend({ ... })
connect([ ... ],{
  resource: {
    getData(params){  return fetch(params.href) }
  }
})

This should allow:

  • {{baseRestType._links.stack.value}}
  • {{baseRestType._links.stack.promise}} etc

Thanks for digging into this! This is definitely useful background info… For my particular case I was able to update the server response to populate the complex field using a Spring Data Rest Projection:

@Projection(name = "deployInfo", types = { Deploy.class })
public interface DeployInfo {
...
    Stack getStack();
}

and GET /vulcan-service/v1/deploys?projection=deployInfo