resgateio / resgate

A Realtime API Gateway used with NATS to build REST, real time, and RPC APIs, where all your clients are synchronized seamlessly.
https://resgate.io
MIT License
689 stars 67 forks source link

collection format #54

Closed mmardinian closed 5 years ago

mmardinian commented 5 years ago

Hi, Nice work with Resgate. I am having fun with it since a few days. Not I want to complicate a little bit my model. But, on a GET request, complicated JSON struct don't seems to pass.

For instance I return this Json structure on a Get request: { "result": { "collection": [ { "description": "Room1", "device.description": "Room1", "device.icon_name": "audio-card", "device.intended_roles": "music", "device.model": "WX-010", "device.string": "[10.0.140.181]:5000", "index": 0, "name": "raop_output.Room1.local", "path": "system.audio.raop_output.Room1.local", "subscribe": [ { "format": "pa_sample_spec", "methode": "createStream" }, { "format": "sample", "methode": "writeStream" } ], "uuid": "raop_output.Room1.local" } ] } }

But, the Get request return this: { code: "system.internalError", message: "Internal error: Internal error: Invalid value" }

Could you take a look at it please? Thanks,

Michael

jirenius commented 5 years ago

Hi Michael,

Glad you are trying it out!

When doing nested/complex structures, you need to work with resource references. The RES protocol only allows collections and models to have values that are either primitives or references to other resources. That means, a model may only contain a reference to a collection (or another model), but not the collection itself. And a collection may only contain references to other resources as well.

See: Res Protocol#Values

There are multiple reasons why the protocol doesn't allow resources with complex nested structures, but I won't go into design decisions. Instead I can tell you how it is meant to be done using resource references :)

I can see the following 5 resources in your structure:

service.rooms

[ { "rid": "service.room.1" } ]

service.room.1

{
    "description":"Room1",
    "device.description":"Room1",
    "device.icon_name":"audio-card",
    "device.intended_roles":"music",
    "device.model":"WX-010",
    "device.string":"[10.0.140.181]:5000",
    "index":0,
    "name":"raop_output.Room1.local",
    "path":"system.audio.raop_output.Room1.local",
    "subscribe": { "rid": "service.room.1.subscriptions" },
    "uuid":"raop_output.Room1.local"
}

service.room.1.subscriptions

[
    { "rid": "service.subscription.1" },
    { "rid": "service.subscription.2" },
]

service.subscription.1

{
    "format":"pa_sample_spec",
    "methode":"createStream"
}

service.subscription.2

{
    "format":"sample",
    "methode":"writeStream"
}

I've made up all the resource ID's . You obviously should name them differently. Especially the service.subscription.x, since I don't know if the subscription objects might be shared, or if they are unique for each room. In such a case, they might more suitably be service.room.1.subscription.x.

When you send a Get request for the service.rooms resource, Resgate will follow the references and return all these resources in one single response to the client.

Did that make it clearer?

If you still have questions, don't hesitate to reply! I like explaining these things :) .

/Samuel

jirenius commented 5 years ago

I can also add that, I am currently working on a proper website for Resgate, resgate.io , containing all the guides and examples one need to learn these things. The section on Nested Resources does explain this exact part.

Too bad the site is not public yet. But I plan on having it made public before the end of the year!

jirenius commented 5 years ago

Closing topic