quarkus-renarde icon indicating copy to clipboard operation
quarkus-renarde copied to clipboard

How to generate REST endpoint URLS in Templates?

Open tmulle opened this issue 2 years ago • 4 comments

Hi,

In Play framework, they appear to let you generate REST endpoints in the HTML using something like: jsRoutes.controllers.Blogs.view(parseInt(full.id));

and things like <img src="@routes.Assets.at("images/checkmark_12x12.png")"/> to point to images, etc.

Is this possible in Renarde?

I'd like to also return JSON data to populate HTML UI components which use Ajax to fetch the data from our backend endpoints running in the same app.

something like "http://localhost/videos/listJson" and have this URI autogenerated in our templates.

Does the {uri} do this? and if so does it handle parameters as well?

Thanks.

tmulle avatar Sep 18 '22 20:09 tmulle

https://quarkiverse.github.io/quarkiverse-docs/quarkus-renarde/dev/index.html#_obtaining_a_uri_in_qute_views answers this, you can use {uri:Blogs.view(parseInt(full.id))}.

Let me know if this works for you, and feel free to send a PR to improve the docs if you think it's unclear or incomplete :)

FroMage avatar Sep 26 '22 15:09 FroMage

Thanks..but I the issue I'm having is that I need to have the replacement done at runtime in the javascript.

Things work fine when I just need to replace values at build time in the templates themselves. For right now, I simply hard code the URLS in the javascript functions that need to be run in the browser.

It looks like in our legacy Play web app the Play framework has a method to generate a jsRoutes java script class which has all of the backend URIS calculated, including parameters.

So, in our main Play Framework controller we have something like this:

/**
     * These routes are referenced as Javascript functions in the templates
     * @return
     */
    public static Result jsRoutes() {
        return ok(
            Routes.javascriptRouter("jsRoutes",
                routes.javascript.Artifacts.details(),
                routes.javascript.Artifacts.edit(),
                routes.javascript.Artifacts.removeFile(),
                routes.javascript.Artifacts.changeArtifactStatus(),
                routes.javascript.Artifacts.getReleaseNotesByVer(),
                routes.javascript.Artifacts.getKnownIssues(),
                routes.javascript.Artifacts.promptDownloadToken(),
                routes.javascript.Downloader.downloadFile(),
                routes.javascript.Downloader.downloadUserFile(),

and then in all of our templates we request the generated JS file like this:

<script type="text/javascript" src="@routes.Application.jsRoutes()"> </script>

The returned file from the Play server looks like this:

var jsRoutes = {}; (function(_root){
    var _nS = function(c,f,b){var e=c.split(f||"."),g=b||_root,d,a;for(d=0,a=e.length;d<a;d++){g=g[e[d]]=g[e[d]]||{}}return g}
    var _qS = function(items){var qs = ''; for(var i=0;i<items.length;i++) {if(items[i]) qs += (qs ? '&' : '') + items[i]}; return qs ? ('?' + qs) : ''}
    var _s = function(p,s){return p+((s===true||(s&&s.secure))?'s':'')+'://'}
    var _wA = function(r){return {ajax:function(c){c=c||{};c.url=r.url;c.type=r.method;return jQuery.ajax(c)}, method:r.method,type:r.method,url:r.url,absoluteURL: function(s){return _s('http',s)+'localhost:8080'+r.url},webSocketURL: function(s){return _s('ws',s)+'localhost:8080'+r.url}}}
    _nS('controllers.Artifacts'); _root.controllers.Artifacts.details = 
          function(id) {
          return _wA({method:"GET", url:"/" + "downloads/" + (function(k,v) {return v})("id", id)})
          }
       
    _nS('controllers.Artifacts'); _root.controllers.Artifacts.edit = 
          function() {
          return _wA({method:"POST", url:"/" + "ws/downloads/edit"})
          }
       
    _nS('controllers.Artifacts'); _root.controllers.Artifacts.removeFile = 
          function() {
          return _wA({method:"DELETE", url:"/" + "ws/downloads/"})
          }
       
    _nS('controllers.Artifacts'); _root.controllers.Artifacts.changeArtifactStatus = 
          function() {
          return _wA({method:"POST", url:"/" + "ws/downloads/changeStatus"})
          }

... more functions

This file is then run in the Javascript runtime and simply provides the URL and parameters for the Ajax requests.

This seems like something Renarde might be able to also do? Since you autogenerate the REST endpoints by scanning the classes? I thought I heard you say that on your YouTube video.

Just an idea, I have no idea what it would take to implement that or how closely to Play framework you want Renarde to become. But so far it was really close to our legacy Play framework.

tmulle avatar Sep 26 '22 15:09 tmulle

Ooooh, this is very nice indeed. I'd like to add this feature. Do you think you'd be up to contribute it? I can help you get started if you want. Otherwise I will do it, but it might take some time before I have time for this.

FroMage avatar Sep 26 '22 15:09 FroMage

Like you, I don't have any time at the moment with my current workload to start on this. I also don't know all of the details of how the Play stuff works so would need to dig into that. But if I free up after this legacy conversion then I might give it a shot assuming you or anyone else has completed it.

tmulle avatar Sep 27 '22 12:09 tmulle