xyncro / freya

Freya Web Stack - Meta-Package
https://freya.io
Other
330 stars 30 forks source link

Hypermedia Support (General) #62

Open kolektiv opened 9 years ago

kolektiv commented 9 years ago

Referencing #49 as perhaps a concrete question, come up with some strategy for what to support and how in the hypermedia space. At first glance the space is confusing and difficult to tell what's actually adopted and how prevalently. Off the top of my head as a start for ten in hypermedia standards...

Any others to consider obviously? At the moment my plan is to experiment with HAL and then see if some commonalities start looking a bit emergent when I implement something else. It would be great to end up with a common model which could output any format, but I'm not sure that's realistic without ending up with a lot of stringly typed things (which is pretty much antithetical to Freya). However, I'm not ruling that out...

haf commented 9 years ago

JSON-anything has mostly missed the point of content negotiation, imo. JSON-LD seems to be xsd all over again.

Linking seems common, specifically Siren, HAL, Uber.

I've looked into HAL a bit more and it's mostly a single level deep, so you could represent links etc with a record and lists, without making it all stringly typed, but I think the hardest step would be to render models into this record representation in a nice way; or you could just make it a DSL that 'remembers' how to output itself and finally outputs itself when it has a fully serialised model.

Then the question becomes; how to synchronise the model's rendering and therefore links to the underlying data representation? And what about APIs like I write which contain both commands, queries (GET-able resources/read models) and events?

kolektiv commented 9 years ago

On the JSON-anything point - hmmmm. I kind of agree in principle, but it's usually a common case in my experience that an API usually just defines itself by the intentions of the creator. Being able to actually serialize representations to anything that the developer didn't plan for at code time doesn't really exist. Given that, at the level of abstraction following an actual hypermedia standard represents, I don't mind too much saying "this standard imposes that your API is JSON - if you want lower level and more control, there are nice ways of building your own abstraction if you wish".

The Freya hypermedia support is going to have to be pretty opinionated I think - but I think we can be because we should be able to make it that you can always go lower in the stack if you want to instead (I hope!).

To start with I'm probably going to be making an assumption that people will be providing resources which can be represented as JSON (in a Fleece pseudo typeclass way I think) and working from there, but this is very much an experiment at the moment!

Do you have an example of the kind of API you're talking about? I think I know what you mean and design things that are similar, but it's always good to have someone else's work to validate assumptions!

Cheers!

panesofglass commented 9 years ago

I just added HTML to the list. @mamund has a good list here. In addition, I think it best to model hypermedia support in terms of H Factors.

Another possibility is to model by affordances, though I think this would be more difficult as you would need to know the exact structure of each media type.

panesofglass commented 9 years ago

It's also worth pointing out that Hydra is really the hypermedia piece associated with JSON-LD. The latter provides semantics for Linked Data, which may open a whole new area of exploration. While we may support it, I think it better to try to start with just the hypermedia aspects.

panesofglass commented 9 years ago

@kolektiv, I know you are hard at work on Chiron, but I was curious whether you had looked at FsPickler. It supports general serialization, as well as pickler combinators, which should be roughly similar to what you are building. This might offer more options to users. Thoughts?

haf commented 9 years ago

FsPickler is a 'binary' serialiser in the sense that it's not a serialiser for data; but a serialiser for runtime structures.

panesofglass commented 9 years ago

@haf, it has both XML and JSON outputs. I thought that might be useful. Aren't the structures important?

kolektiv commented 9 years ago

While FsPickler has JSON output, it's not really recommended for "user facing" serialization. The JSON it produces and consumes is not very JSON like, but a representation of serialized structures. Form their page:

FsPickler is NOT: a general-purpose Xml/JSON/BSON framework. a library designed for cross-platform communication.

I'd love to use it if it was, but I haven't found anything which hit quite the right requirememts for me - hence Chiron :)

panesofglass commented 9 years ago

@kolektiv, cool, just wanted to check. I assumed it was something like that.

Vidarls commented 8 years ago

So, I'm going to need to do hypermedia by the looks of my current project requirements.

I'd be happy to contribute back my code, only problem is that this will be a severe case of "Vidar-does-stuff-he-knows-nothing-about" (tm).

So I am in need of mentoring to guide my work if it is to be of any value to Freya.

In my mind I'm going to need:

(note: I may be way off target here, as I have never done a hypermedia API before)

Also: This is an old issue, are there any work in progress that I should base any work on?

kolektiv commented 8 years ago

It should certainly be possible to do something good, but it's a fairly involved area if you dive into the theory (which you probably don't need to do too deeply). I've had a few ideas over time, but they've all been more abstract than are likely to make sense for you right now. However, they are probably a useful starting point.

It's probably worth maybe having a quick Skype chat or Google Hangout or something to see what the needs look like and what thinking already done might be relevant - and generally think through some ideas - if that's helpful? That should lead towards a good starting point from which a more general solution may be derived...

Vidarls commented 8 years ago

I understand it is quite the complex subject matter. (And also a subject matter where a lot of devs have very strong feeling about what is "the-correct-way" (tm).)

Usually what I'd do when facing these kinds of problems is to solve my concrete instance of the problem, then see if I can refactor to some more generic re-usable code that can be re-used for similar problems.

In any case, a Skype call to point me in the right direction would be much appreciated. What timezone are you in?

kolektiv commented 8 years ago

Sounds a sensible approach! I'm basically UTC :) I could probably do a chat either tomorrow evening (Thursday) or possibly Saturday morning? If either of those help? It's a fairly hectic week in my "real job" this week :smile:

Vidarls commented 8 years ago

Won't be able to start working properly on this until next week I believe. Just wanted to be a bit up front to get an understanding of current status. I'll ping you somewhere on the internets to make skype arrangments.

kolektiv commented 8 years ago

No problem at all - no rush from this side, whenever is good for you :smile:

On 27 January 2016 at 14:54, Vidar Løvbrekke Sømme <notifications@github.com

wrote:

Won't be able to start working properly on this until next week I believe. Just wanted to be a bit up front to get an understanding of current status. I'll ping you somewhere on the internets to make skype arrangments.

— Reply to this email directly or view it on GitHub https://github.com/freya-fs/freya/issues/62#issuecomment-175666598.

Vidarls commented 8 years ago

So, it looks like "next week" was a bit optimistic, but now finally I am about to start implementing some hypermedia support in my app. And if possible I would like to contribute back any reusable pieces.

I'm going to start with hal+json cause it is super simple, and covers my current needs quite well.

TODO:

I will start building something that will work for my current domain and app, and try to present to anyone interested any bits and pieces that may be reusable.

Any input / guidance / thoughts from previous experiences are very welcome.

Typed paths in an ideal world

type MyTypedId = MyTypedId of int
type MyOtherTypedId = MyOtherTypedId of int

myPath = TypedPath<MyTypedId,MyOtherTypedId>("/my/{typedId}/and/{otherTypedId}")

myUrl = myPath.Generate(MyTypedId(1),MyOtherTypedId(2))
// /my/1/and/2

//When requestes:

let (myRequestedId:MyTypedId) = mypath.TypedParam1

Some thoughts on representation

A hal representation on the wire is just a normal object with some optional properties of _links and _embedded the rest of the properties are domain specific. If we are to provide some generic container type it would require stringifying all properties into a dictionary / map type with runtime rules.

Given that creating record types are so low cost to create, and only two "special" kind of properties are required for HAL I believe we could just use normal record types for the wire representation. Makes serialization simple too.

(ping @kolektiv )

kolektiv commented 8 years ago

Sounds good! I'll be interested to hear how you find things, certainly HAL is a simple (and good) place to start. I'm less sure about the typed paths side of things, I tend to find that the routes plus additional optics gives a nice story around that, but I'm certainly open to alternatives.

Vidarls commented 8 years ago

I kind of just had a some sort of epiphany with regards to optics and lenses and morphisms. Now I just need to get past the "lens all the things" period that comes after gaining some new knowledge. Suffice to say that lenses and strongly typed stuff goes nicely together.

So far it seems like there might not be much need for boxed code to do hal and hypermedia. It might be that a recipe in the docs is better. So much is lost when you have to make the code generic enough to be usable for others, and all the building blocks are already in Freya there to very easily do the responses. IMO some repetition to get more explicit specific code is better than overly generic and stringyfied code.

Some refinements in how content negotiation is done might be useful, but no sure until I've gone through the next stretch of coding.

Will report back when I come back up for air :-)

Vidarls commented 8 years ago

The combination of UriTemplates and Optics turned out to be very powerful and flexible and actually allowed me to quite easily do the roundtrip:

So now all is ready for easily generating links for hypermedia relations (yay)

Interesting note:

I spent about 5 hours working on this and refactoring my complete app into using the new scheme. No testing / running / debugging was done during work.

And once it compiled it worked! I don't think I've ever experienced similar with C#, particularly not when combined with learning new stuff.

I will get back with a small write up and some code samples, but now time for some sleep.

kolektiv commented 8 years ago

Great to hear! That was what I had in mind when designing the way that routes would work - making matched data available through optics means that composing those optics further to give whatever control over types you want becomes "just more optics" rather than a special case. Basing the routing on URL Templates also means that generating URLs is just the dual of matching URLs (with some limits, but less over time).

I'm glad that's actually working out in practice! Really looking forward to reading whatever write up you have time for - definitely interested in experiences with people using Freya (who aren't me! :smile:)

robsiera commented 8 years ago

@Vidarls Any update on you progress?

Let me share a link to an overview of current standards, their state and the aspects they cover. Personally I'm currently looking for json api support in F#

Vidarls commented 8 years ago

tl;Dr:

You can do it, it will be beautiful, but you have to build it your self from the components provided by Freya.

The long answer:

@robsiera Well, the good news is that I got some nice stuff working. The bad news is that I had to abandon the company of Freya due to non-technical reasons, so I have not been able to refine my solution anywhere near as much as I would have liked to.

I have not looked at json api (my implemantation is for HAL), but I generally found that the composability for Freya enables you to pretty much get exactly what you need, and build yourself a nice little DSL for it as well. But obviously, as you extend the requirements to include incoming data / schema stuff it becomes more complicated.

btrepp commented 7 years ago

Anyone made something amazing with freya like this and have some examples I can look through?.

I've thought the whole freya config/computation expression style could be layered on to have AtomPub and possibly OData like state machines. Unfortunately I haven't gotten the time to further play with this idea... yet.