-
Notifications
You must be signed in to change notification settings - Fork 57
Automatic path-to-object serialization/deserialization #20
Comments
Hello, |
Good point @jmdesprez, fixed :) |
Hello, BTW I've start a small POC about this feature :) For now, it's located in a dedicated project: https://github.com/jmdesprez/kweb-urlparser At some point of the algorithm, I have to fetch subclasses of the entity (Root, Friend and Settings for example). I've implemented this in two ways:
Let me know if this POC match what you have in mind :) |
Ah, fixed the typo :)
Awesome!!
Check out this library, it might be helpful https://github.com/MehdiK/Humanizer.jvm
Note: I'm using https://github.com/MicroUtils/kotlin-logging (which is an interface to slf4j). I only have a time for a few quick comments now but will try to spend more time on it ASAP. I suggest you post to #kweb on Kotlin Slack, might get some good feedback there too. |
A few more comments/questions :) MinorIn tests:
Why Conceptual, what conventions should we establish regarding "subentities"?I realize it's probably from the examples I came up with, but I'm still not 100% sure about the This isn't really about your implementation, it's more about establishing some intelligent conventions - and RESTful URL naming isn't something I've given a vast amount of thought to yet. At least now we have two people to bounce ideas back-and-forth :)
What should What's the significance of Any thoughts on how we handle parameters, eg. What about the rest of the URL?Another question is whether we should only worry about the path portion of the URL, or should this mechanism translate the entire URL to objects - possibly including the protocol (http/https), hostname, and port? eg. Sorry, I know I'm providing a lot more questions than answers- work so far is really great, I think we just need to think through a few usecases in order to establish some good conventions. |
No problem, that's why I have push the project "as is" ;)
I should have put a 'TODO' on this :) I've no particular reason other than liking Optional and Functional Programming :)
I don't think one solution is better than the others, it's mainly a matter of preference. Perhaps the exception can carry an error message if needed. About the REST APIMy view of it is "data oriented", I see it like a box in a box in a box in .... That's why I like the idea of creating and entity from the URL :)
My way of visualizing this (maybe I'm wrong) is like this:
Moreover, let's assume for the example that thoses API make sens:
In this example
Both URL should be considered as equals I think. How we handle parameters?I think we can bind a parameter to a property. For example
So it's almost like a binding between a path parameter and a property but with one exception. Extra parameter should be discarded whereas an extra part in the URL should end with a 404. For example, given the class What about the rest of the URL?Including the scheme, hostname and port is a good idea. Like for the URL parameters, we can store them into the class property. Maybe we can work by convention here, if the class have a property named "domain" then we will store the domain into it. Same for "scheme" and "port". For example: |
Ah, in Kotlin -
I think what you're describing is appropriate for a REST API to be accessed programmatically, however in our case the URLs reference a user interface in a particular state, rather than just information to be presented (the UI can be interacted with, of course). But maybe this is irrelevant here - sorry, I'm thinking out loud :)
interesting, yes, that is very intuitive.
Yes, although we could also have an open class with properties scheme, domain, and port, and have the user's data class subclass from that... would allow us to rely on type safety rather than just convention. What do you think? |
Just thinking about plurals, I think probably
|
Yep, I know this already ;) but I still prefer the Optional. Actually, not the Optional from JAVA (I don't like it) but I use http://www.javaslang.io/ and https://github.com/MarioAriasC/funKTionale. Both propose an
Ok, I'm really sorry :-( I've completely miss this point :-( I've seen this project long time ago (before this conversation) and I've get a quick look then decide to put it in my "study list". I haven't realized the importance of the GUI.
+1 Keep it simple :) So, I will have a closer look at Kweb asap to improve my understanding |
Yes, sorry, I didn't mean to sidetrack us on a conversation about nullability, or to lecture you on something you were already familiar with :) I'll take a look at the libs you mention.
Oh, well I was thinking about it and I'm actually not sure that it matters too much for the purposes of the piece you're working on. Also this stuff is mostly still in my personal working branch, so totally understandable that it might not have been clear. The way Kweb works (or will work soon!) is that you "bind" different parts of the browser DOM to stateful data on the server. This state can be local to the user's "session", or it can be persistent state stored on disk or in a DB. If the state changes then the UI is automatically modified accordingly. This is consistent with the Single source of truth principle, combined with the observer pattern. So, for example, I can "bind" the text within a The URL is treated as just another piece of state, which can be changed by the user (depending on what URL they visit), or by something else in the code. If the user visits a URL then Kweb builds the UI accordingly, but the programmer can also modify the URL by modifying the state, and then the UI will automatically update accordingly. If the user visits a URL, Kweb will respond with the UI in the appropriate state, for example visiting /users/123 might show you information about user 123 and give you the ability to edit that user. In any case, for these purposes the only goal is to have an automatic way to convert a URL into a Kotlin object and back again - so that we can encapsulate the actual structure of the URL in a typesafe way. I'm very happy to discuss further if it would be helpful. |
@jmdesprez I'd like to pull this into the main codebase fairly soon - and major outstanding improvements in the wings? |
It was very interesting to have your vision of "Null safety vs. Option" and I think we can talk about this for hours :) But I was afraid to "spam" this conversation :) If you are happy with the POC you can surely use it and pull it into the main codebase :) But, there one point that may need to be check. I'm not absolutely sure that the cast is safe (I've put a TODO on it) I've no idea for an improvement right now. If ideas start coming I will create a pull request in kwebio ;) Thank you, it was a very interesting conversation (and it's a very interesting project too :) ) |
Ok @jmdesprez, initial integration done: https://github.com/kwebio/core/blob/url-parser/src/main/kotlin/io/kweb/routing/UrlPathParser.kt The major thing I need to do is have it throw a Currently unit tests will fail because of the lack of a UrlParseException. Still getting a good understanding of your code so haven't figured out how to do it yet - any pointers appreciated :) |
Ah, and of course I totally forgot about the other side of it, taking an object and converting it into a URL (ie. same process but in reverse). |
Hello, #23 should do the trick for the URLParseException. Because a Edit: I forgot to mention that:
|
Regarding the entity -> path mechanism, we may get into trouble if the entity have many constructors (because each constructor will be translated into a different URL). I've do a small POC we can start with. To solve the problem above, I've expect it will use the primary constructor to build the URL. Sorry I don't have too much time, I've not create a POC project or tests (I've test it manually using a main and it seems to work great) Here is the POC:
|
Awesome, I've merged your POC and added some tests for it, a few of them are failing (I didn't test any URLs ending in I have to drive to Dallas today for a meeting (7 hours 👎 ) but will try to get to this this evening if I'm not too fried, or failing that tomorrow. If you feel like taking a look in the meantime please feel free :) Then I think with some JavaDoc it will be ready to be deployed. |
Ok, got the unit tests working, made a few more changes, and its now pushed to master. Still need to document - dokka isn't living up to its promise :/ |
Going to close this, although #25 needs to be addressed before this is usable in practice. |
Note: While it will require a decent understanding of Kotlin reflection, this is a very self-contained project and thus might be an ideal choice for someone interested in getting their feet wet as a Kweb contributor. If you want to tackle it please comment below to avoid duplicated effort
I've been working on routing, and have an approach that's both relatively simple and I think very powerful.
One thing that would add greatly to it is some code that could convert a URL path like
/users/123/friends/94
into an object representation of the path, likeUsers(id=123, Friend(id = 94))
, similar to how Gson converts JSON into object representations and back again.For example, let's create an object representation of our webapps paths as follows:
Note the use of sealed classes, this will be nice when we use
when
expressions to render the paths.Here are some paths and the object equivalents:
/users/32
->Entity.User(32, UserEntity.Root())
/users/152/friends/22
->Entity.User(152, UserEntity.Friend(22))
/
->Entity.Root()
Additionally, while defaults should be sensible and consistent with REST conventions for URL format, it should be possible to use annotations to override the default translations from path to object (much as with Gson).
The text was updated successfully, but these errors were encountered: