Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Should Siren be using absolute URIs? #75

Open
velveteer opened this issue Feb 10, 2018 · 6 comments
Open

Should Siren be using absolute URIs? #75

velveteer opened this issue Feb 10, 2018 · 6 comments
Labels

Comments

@velveteer
Copy link
Member

Right now the client knows one absolute URI for this API -- one which points to the correct API environment. This is used as a base to resolve all relative entity links like /characters, which in this example is acceptable because this is the root entity and the client needs to know this entry point at the bare minimum.

However, the Siren spec appears to not have much to say about relative URIs. And the current Siren implementation is relying on relative URIs in most links. Which leaves us to our own devices for resolving links in the client. Of course it's a solved problem for any Siren entities coming from this API because the client has the host hard-coded and can append relative URIs to this host, but CollectionJSON links are using relative URIs and the client does not know their host.

My initial solution was to tell the client the base absolute URI for Collection links, just as we do for Siren links. This was deemed unacceptable because we require the client to know things that Siren is not telling it. The proposed solution in the API gives absolute URI links to collection relations on the root entity -- which are helpful insofar as the client can extract the host and append it with relative URIs to resolve links. Or the client can use these absolute URIs to fetch the collections, cache them in the client, and resolve links by querying the cache via relative URIs (which map directly to the href property on collections). It appears this latter behavior was intended for the client to implement. But in both approaches it means we still have to use relative URIs on character creation, in violation of the url type defined on the create-character action fields.

I believe I see the problem with the CollectionJSON implementation, since items are static and their hrefs cannot be determined at runtime (a collection doesn't know its environment). Which means we would need distinct collections for each environment? I admit this does seem tedious, but isn't this how it should be if every environment has its own audience? Or is the collection server exempt from this?

Could we solve this with another Siren relation? Something that tells the client a link must be looked up in a collection and not resolved via its href? And then we must remove the url type from character disciplines and races, perhaps making them simple strings. In this case the validation for character creation is handled implicitly because the client will only let users choose values from the collection (e.g. in a select dropdown), so URI validation is moot.

Should we attempt to use absolute URIs everywhere? It does make the client easier to implement, but I'd like to know your thoughts on what the major obstacles are.

@alunduil
Copy link
Collaborator

I'll try keeping things respective to particular paragraphs and in order so we have a somewhat clear correspondence for these notes.

Completely agree and have nothing to add.

This is true and one of the things I remember when figuring out siren the first time. They don't specify if URL encompasses relative and absolute URIs. In the end, I took a note from the URI RFC and collection+json's thought process that any relative URIs would be RFC style appended (see https://hackage.haskell.org/package/network-uri-2.6.1.0/docs/Network-URI.html#g:5 for more details). The reason we relay on relative links in the siren document is due to the difficulties in crafting an absolute URI from a service. We can go with the straight-forward: I'm configured with my base URI and will prepend it to all URIs but then we break if we move the service or otherwise change it's name and forget to update this parameter. Trying to automatically deduce this information is also tricky at best. Getting the host portion is generally straight-forward: grab the host header in the HTTP request, but what about the scheme? I may be behind an SSL terminating proxy of some sort and never know that SSL is in play but my users will have broken URIs if I don't specify it. I would like to consider that all collection+json URIs that are received as part of the API should be forced to be absolute but that means that the source of that information must be forced to provide an absolute URI.

I still contend that any non-local relative URIs are a bug that need to be rooted out. For example in the document at #73, the race and discipline links are non-local and should not be relative. I also believe these are the relative links we are actually having problems with. These are relative because the API allows the client to submit a relative URI when creating a character. This should not be allowed. With only storing absolute URIs the problem is mitigated as any relative references will be local to the document requested and can proceed as outlined previously. Let me know if this makes sense as I believe it fixes the HTML validation problem as well.

The collection server is unaware of the authorization but I'm not sure that's what you're asking on this one. I will simply refer to the earlier statements on determining the absolute URI from inside the API.

We could but I don't believe that is necessary. We should be allowing the user to select a race or discipline and then using the request URI and the response URI craft the absolute URI that is submitted to the API. This is why I've been repeatedly saying the API should be validating this submission. It also corresponds to your HTML uri type being an absolute URI. I'd rather not make the assumption that the default list of races and disciplines are the only options. Having a way for a user to specify their own absolute URI to a valid and parseable race or discipline is a nice way for them to customize their game. So ensuring that we only submit absolute URIs is very desirable.

I've outlined where relative URIs are preferred due to ease of implementation but everywhere else I'd want to use absolute URIs. Any URIs sent from the client to API should be absolute which will mediate a lot of the issues we're seeing right now.

Let me know what you think of this rambling response, but I think we agree just need to make sure we picture it the same.

@velveteer
Copy link
Member Author

I still contend that any non-local relative URIs are a bug that need to be rooted out. For example in the document at #73, the race and discipline links are non-local and should not be relative. I also believe these are the relative links we are actually having problems with. These are relative because the API allows the client to submit a relative URI when creating a character. This should not be allowed. With only storing absolute URIs the problem is mitigated as any relative references will be local to the document requested and can proceed as outlined previously. Let me know if this makes sense as I believe it fixes the HTML validation problem as well.

Yes, I believe this is exactly the main issue. For now I will create characters using absolute URIs, and scrap the current ones I am developing with since they are malformed.

Because the HTML5 form types (but not necessarily validation, for example can you specify optional fields?) are dictated by Siren, what a discipline and race turn into at the form level is a text input with URI pattern validation, and I don't think we want to make users type in URIs. I suggested a select input with the options provided by the discipline and race collections, and this is also not something apparently described in the Siren schema. Of course we could add an option for manual URI input for customization. Which leads to...

We should be allowing the user to select a race or discipline and then using the request URI and the response URI craft the absolute URI that is submitted to the API.

Can you give an example of how this could be derived with the current Characters entity? Of course I want to send absolute URIs to the API, even though I get relative URIs from the collection items. What I have is this:

  • Links that point to collections, like http://r.collection.dungeon.studio/earthdawn/4e/races
  • Items from those collections with hrefs like earthdawn/4e/races/troll

These items would become the values in the form input, as described above. Since we do not want to have users type in URIs (our URIs, not custom), right? So at this point when the form is submitted I have a race field with a value of earthdawn/4e/races/troll.

The proposed implementation, as far as I can tell, is that the client remembers the HTTP Host of each requested link. So for example when I request the disciplines and races collections, I could actually be saving these as a product of their host and response, like Tuple URI ResponseType. In my case, because I have to define my DSL at the functor level, ResponseType is a tagged sum that includes Siren and CollectionJSON types. I could map over this structure to get back Tuple URI RelativeURI and use these under the hood as the form input values. Then on form submission I can find these structures and turn them into absolute URIs.

A bit of work, but I think it makes sense. It's just that this is something the client is assumed to implement, and not something the Siren relations make clear.

@alunduil
Copy link
Collaborator

alunduil commented Feb 10, 2018

I believe delete is implemented so give that a go for removing the characters you've created. Otherwise, let me know and I can purge them from the datastore.

I'd have to check on optional fields, but I believe so. I think an option of typing in a URI should be available but the drop down or other selection with our list of defaults should be preferred.

Hmm, does purescript have similar URI handling to Haskell? In Haskell I'd simply say the following, and fix any ensuing errors in either URI.

item `relativeTo` collection

This would result in (for your given example): http://r.collection.dungeon.studio/earthdawn/4e/races/troll. If it didn't then it'd be a bug in either the relativeTo implementation or the relative URIs for the items.

That approach sounds reasonable but smells funny at first glance. I'd have to see an implementation to give it a full vet.

Unfortunately, yes, siren does not make this clear but we are following standard relative and absolute semantics from URIs and other document types. So it shouldn't be too bad and should be very portable to other MIMETypes if we so choose.

@alunduil
Copy link
Collaborator

So I looked at a couple of ways to force the API to handle this and right now I'm leaning towards a Valid type that can wrap other types to show they've been validated.

class Valid a where
  valid :: a -> Validated a

I'm thinking a functor and applicative instance make sense for this but not sure about monad yet. What do you think?

@alunduil
Copy link
Collaborator

Copy link

-| This issue has not been updated in 90 days. It will be closed in 90 days if no further activity occurs. Please respond if you would like to keep it open.

@github-actions github-actions bot added the stale label Sep 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants