Giter Club home page Giter Club logo

Comments (13)

lengarvey avatar lengarvey commented on June 19, 2024

@jodosha this seems like it should be an issue on https://github.com/lotus/router instead?

from hanami.

jodosha avatar jodosha commented on June 19, 2024

@lengarvey Lotus::Router is agnostic about Lotus applications and I'd like to keep it as it is. Probably it would require some new mechanism in Lotus::Router as base for this feature.

from hanami.

lucasas avatar lucasas commented on June 19, 2024

I'm giving attention for this @jodosha. Maybe on Monday I send some code draft.

from hanami.

jodosha avatar jodosha commented on June 19, 2024

@lucasas 👍

from hanami.

lucasas avatar lucasas commented on June 19, 2024

@jodosha where the application is creating this anonymous router? And where double routing dispatch is being made? Thanks dude

from hanami.

jodosha avatar jodosha commented on June 19, 2024

@lucasas The "anonymous router" is something like this:

# config.ru

# this router instance is anonymous
run Lotus::Router.new {
  mount Backend::Application, at: '/backend'
  mount Frontend::Application, at: '/'
}

It's the only way that we have now for dispatch HTTP requests for multiple applications.
The full explanation is in the README.

from hanami.

lucasas avatar lucasas commented on June 19, 2024

Hey @jodosha, I've implemented a draft to accomplish flatten routes, registering a lot of applications.

Some changes were made on lotus-router to contemplate this. Now, Lotus::Router can receive an option named mount_at, which will be used to define a namespace for the defined routes. More details can be found here: lucasas/router@45ebf37#diff-7874fa6a25a9c35022a569e25b04bfa4

But basically, now you can do the follow:

Lotus::Routes.new(mount_at: 'backend') do
    get '/flowers',     to: 'flowers#index'
end

This is completelly equal with the code below:

Lotus::Routes.new do
    namespace 'backend' do
        get '/flowers',     to: 'flowers#index'
    end
end

Another change on Lotus::Router is that it now has an each method. This is useful to list (and copy) all routes defined into a Lotus::Router instance. So that you can iterate over these routes:

@router.each do |route|
   puts route # => it will print #to_str from Lotus::Routing::Route
end

Lotus itself, suffered some changes too.

Lotus::Configuration allows the user specify a mount point to the given Lotus::Application, this information is passed to Lotus::Router instance. More details here: lucasas@2b18990

module Backend
  class Application < Lotus::Application
    configure do
      root File.dirname(__FILE__)
      load_paths << [
        'controllers',
        'views'
      ]

      layout :backend

      # defining mount point of this application
      mount_at 'backend'

      routes do
        get '/login', to: 'sessions#new', as: :login
      end
    end
  end
end

The most important change ocurred here: lucasas@2b18990

The new class called Lotus::Routing::Builder is where the magic happens. There, Lotus copies all routes defined into each application storing it in a single Lotus::Router instance, the call method is redefined, and now is responsible to deal with all requests coming. It can be used like in the code below:

run Lotus::Routing::Builder.new {
  mount Backend::Application
  mount Frontend::Application
}

As each application defines its own mount_at point, it's not needed to pass at option when calling the method mount. But I'm not sure about this interface. Maybe, instead of call mount_at method inside configure, we can pass at option in the code above.

Next steps:

  • raise an error when two applications have the same mount point (aka mount_at)
  • improve documentation of all classes
  • create some integration tests to validate all those changes

I'm really want to know your opinion, realize if we are in the same page.

Thanks.

from hanami.

lucasas avatar lucasas commented on June 19, 2024

Hey @jodosha. Thoughts here?

from hanami.

lucasas avatar lucasas commented on June 19, 2024

There is a little bug here to be resolved (thanks @arthurgeek)

As my Lotus::Routing::Builder#call method is not calling @rendering_policy.render(response), Lotus::View is not working with my solution.

I've copied all routes from all applications to a single router, this router just call the recognized destination without pass through Lotus::Application#call which calls @rendering_policy.render(response).

I'm visualizing all possibilities before go ahead. If you guys, specially @jodosha, have some idea to help me, would be great.

One of them is: I could instantiate a new Lotus::RenderingPolicy, use it inside Lotus::Routing::Builder, but it depends on Lotus::Configuration which is unique for each application, so I think this is not a reasonable idea, since each application has its own configurations.

from hanami.

jodosha avatar jodosha commented on June 19, 2024

@lucasas Yes, I know, what you mean. Sorry for not making clear that this was the challenge of this feature, and instead you had to figure out it by yourself. I opened this ticket to brainstorm with you guys.

As we haven't already defined a stable architecture, my proposal is to hold on this, as it feels like premature optimization. We don't want to bend the framework too early.

from hanami.

lucasas avatar lucasas commented on June 19, 2024

Yes, this is really a challenge. I spent today 6 hours trying to figure out how to solve this, and I was intending to work on it in the next days.

As you said, I might give up to do it for a while. But I think that step 1 (Pass to the single applications the :at prefix, so they are aware of the prefix configuration) should be done right now.

What is your opinion?

from hanami.

lucasas avatar lucasas commented on June 19, 2024

As I talked with @jodosha, for while, I'll keep focus on the first feature (Pass to the single applications the :at prefix, so they are aware of the prefix configuration).

Actually, this is done, I'm gonna extract it, create some documentation and tests, before open a PR.

from hanami.

lucasas avatar lucasas commented on June 19, 2024

Hey @jodosha, in my solution, the first step is coupled to second one, in a way that one doesn't work without the other.

I want to explain what I've done to resolve just the first step.

I've changed Lotus::Loader to respect a given router_namespace defined into Lotus::Application:

module Backend
  class Application < Lotus::Application
    configure do
      router_namespace 'backend'

      routes do
        get '/login', to: 'sessions#new', as: :login
      end
    end
  end
end

module Frontend
  class Application < Lotus::Application
    configure do
      router_namespace 'frontend'

      routes do
        get '/login', to: 'sessions#new', as: :login
      end
    end
  end
end

Into Lotus::Loader#load_rack! I've done:

      application.routes = Lotus::Router.new(
        resolver:    resolver,
        default_app: default_app,
        scheme:      configuration.scheme,
        host:        configuration.host,
        port:        configuration.port
      )
      application.routes.namespace(configuration.router_namespace, &configuration.routes)

It's simple, all routes are defined respecting a router_namespace. Doing that, when Backend::Router.path(:login) is called, /backend/login is returned, step one accomplished.

In my config.ru file, I'm using an instance of Lotus::Routing::Builder:

module Lotus
  module Routing
    class Builder
      def initialize(&blk)
        @router = Lotus::Router.new
        instance_eval &blk
      end

      def mount(app)
        @app = app.new
        @router.mount @app, at: "/"
      end

      def call(env)
        @router.call(env)
      end
    end
  end
end

# config.ru
run Lotus::Routing::Builder.new {
  mount Frontend::Application
  mount Backend::Application
}

As you can see, all application are mounted at the same point ("/"), what's (clearly) a problem, because http_router will recognize request coming to the first registered application. In other words, my solution does not work.

I'm still trying to figure out which approach can solve this problem, I mean, which alternative I have to do achieve first step solution.

from hanami.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.