I interviewed Paul Smith, who is the creator of Lucky. We spoke about Crystal and his path with working on the Lucky framework. I had a great time and think it will be a good episode for people interested in one of the largest web frameworks in Crystal. If you like it, please subscribe and review the podcast so we can get visibility in the podcast players.
Just to clarify the context here is that you can’t have type-safe access to params when you have multiple methods in a single class. If you do something like params[:param_name] then you don’t need not_nil! but that is because there is never a guarantee that the param will exist.
So here is kind of what I mean by needing not_nil!
class MyController
def index
puts id # This will raise at Runtime because `id` is not set for this route
end
def show
puts id # This will work
end
def id
params[:id]
end
end
So this doesn’t use not_nil! but illustrates that the param can be nil and can lead to Runtime errors.
You could use []? and not_nil! but you still have to manually ensure you are using it correctly. There is no compile-time guarantee
class MyController
def index
puts id.not_nil! # This will raise at Runtime because `id` is not set for this route
end
def show
puts id.not_nil! # This will work
end
def id
params[:id]?
end
end
Whereas in Lucky each action has a route defined and thereforce can guarantee that a param exists at compile-time:
class Users::Show < BrowserAction
# Lucky generates an 'id' method that returns the id
route "/users/:id" do
puts id # Works
end
end
This also helps with path generation because the param is required at compile-time: Users::Show.path(id: 123). There are other ways to do that, but the class-based approach made it pretty simple.
Does that make sense?
EDIT: you actually can as @Blacksmoke16 showed below! I’d like to correct my previous statement to can’t do type safe to access params using instance methods/instance vars for the param (I think ).
However, this isn’t entirely true. To clarify that section in the podcast, Athena makes the route’s parameters, arguments in the method. It doesn’t fetch them another method like those examples or Rails does.
class UserController < ART::Controller
@[ART::Get("/user")]
def users : Array(User)
[User.new(1, "User 1"), User.new(2, "User 2")]
end
@[ART::Get("/user/:id")]
def user(id : Int32) : User
User.new id, "User 1"
end
end
Because of this, you get both compile time safety on arguments used within the method, as well as the return value of said method. Nilable arguments are considered optional and will be nil if not supplied (such as for query params for example). Since the actions are just methods, default values can also be used to keep an argument not nilable even if the parameter itself is not provided, say like include_all query param defaulted to false.
@wontruefree you are doing a great job with these podcasts. They are really informative.
After listening to this most recent episode I’ve decided to try out lucky for a new project that is going to be fairly large, instead of using a React JAM Stack front end with Crystal microservices.
@paulcsmith in my above mentioned project, I may need to add in a rest API for most of the site functionality at a later date. Are there any lucky specific paradigms for adding an API alongside the site? Will I be able to easily use the same logic for both the site and the API?
What I do in my site is I just have a folder src/actions/api/.... Inside my api folder are just namespaced actions
class Api::V1::Users::Index < ApiAction
end
class Users::Index < BrowserAction
end
Also note that by default, Lucky comes with both the ApiAction and BrowserAction to handle the two different use cases. Feel free to drop by the gitter chat if you have any questions!
So happy to have you try Lucky! We have a number of people using REST APIs and can help you out if you get stuck. For keeping things DRY we have “Operations” which let you put the logic in an “Operation” class that can be called from a BrowserAction or ApiAction.
I hope you like using Lucky! It still has a ways to go for 1.0 but we’re getting close!
If people are not subscribed to the podcast or in general do not listen to podcasts we have a YouTube channel. We have gone back to Paul’s interview and made it a movie now. Enjoy and subscribe.