-
-
Notifications
You must be signed in to change notification settings - Fork 189
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
[WIP] Encapsulate applications #511
base: master
Are you sure you want to change the base?
Conversation
* `require "kemal"` loads `kemal/base` and `kemal/dsl` * `require "kemal/base` loads only `kemal/base`
aab22b1
to
678adaa
Compare
This is still WIP. I'm still trying to come up with some architectural decisions regarding the API. Option 1: We can allow each application inheriting from Sample code: class MyApp < Kemal::Application
get "/" do
"Hello from 1"
end
end
class OtherApp < Kemal::Application
get "/other" do |env|
pp "2"
"Hello from 2!"
end
end
spawn { OtherApp.run(port: 3000, reuse_port: true )}
MyApp.run(port: 3000, reuse_port: true) Notice the Option 2: We can only have singletons of With this approach, we'll still need to have something like Sample code app1 = MyApp.new
app1.get "/admin" do |env|
"app1"
end
app2 = OtherApp.new
app2.get "/" do |env|
"app2"
end
Kemal.mount([app1, app2])
Kemal.run Eventually we can improve
|
Keep up the great work. Here are my two cents as a new crsytal user; Both options can be possible at the same time. Inherit class ApiApp < Kemal::Application
...
end
# Start just the api
ApiApp.run
# or combine multiple apps together
Kemal.run ApiApp, DashboardApp
# or mount apps to paths
Kemal.run do |mount|
mount '/api', ApiApp
mount '/admin', DashboardApp
end |
Option 2 doesn't provide much benefit. I'm not sure if the whole encapsulating process would really be worth it if only this was the output. A use case for Option 1 is to essentially run multiple servers from one executable, for example providing a separate administration interface which is only accessible via a separate port and can thus be easily secured by making it only locally accessible. Btw. using |
There is https://github.com/vladfaust/http-multiserver.cr which allows to bind multiple servers to a single socket ☝️ |
Nice! 🎉 This code doesn't work: class MyApp < Kemal::Application
before_all do |env|
env.set "key", "value"
end
get "/" do |env|
"Hello Kemal!"
end
end
app = MyApp.new
app.run While this one works: class MyApp < Kemal::Application
get "/" do |env|
"Hello Kemal!"
end
end
app = MyApp.new
app.before_all do |env|
env.set "key", "value"
end
app.run |
@vladfaust No offense, but |
Great to see this happening. We've talk about this before and this is, in my opinion, a killer feature. As an user that have asked for this feature, I would like to share the following thought: The ability to hardcode a few apps and run them on different paths as shown in the examples above is nice and all, but in the end is just a nicer api for what was already possible. Albeit not through a clean api. The real added functionality is being ably to dynamically mount applications on runtime. And, the awesomeness, would be the ability to do that a not-so-small scale. Say, mounting hundreds of applications. This is not possible ATM. For example, say I have a SaaS and want to provide a rest api per user. I could, under the limits of what's reasonable, retrieve the user details from my database, create an app instance for each and run them. Whatever the api is going to look like will be a matter of style/preference. Ultimately this is a less important detail. I would suggest putting the focus on making a larger number of application instances not only doable but performant. It is important to be clear about the amount of apps that would be reasonable to mount: 10? 100? 1000? more? Personally, I don't see much point in doing it for less than say, 50. Sounds extreme but if you think about it, if you want to mount 10 apps, you could easily do it with a workaround like using prefixes as namespaces for your routes, for example with the help of a macro. Keep up the good work. |
@straight-shoota & @sdogruyol any updates on this? I would love seeing this happening :) |
nice work, looking forward to the release. Could either have extendable traps in Crystal, or perhaps a class variable that stores new Kemal apps and the trap will run through the list so even if a new one is created, the same code is written and it handles both. |
Does kemal support preview_mt now? |
Would be nice if this got some traction again. My personal experience on a very small project is that while the un-encapsulatedness of the current implementation gets you off the ground very fast, you quickly run into some state or dependency that need to be shared between routes. This can be solved by top level variables, Singletons and other means, but it's very mind-bending for someone coming from more conventional OO languages. I do like the concept of defining a class and then calling run on that. It's not that it's much more work and it has the added benefit of making state (instance vars) and dependencies (injection) obvious for the new-to-Crystal-but-experienced-in-OO user (and I'd say not too difficult to grasp for the total newbie either). Just my two cents. |
Building on top of @straight-shoota's initial work 👍
This currently builds and runs with Crystal 0.27.0