Kawaii
Kawaii is a simple web framework based on Rack.
** This is work in progress. The API is subject to change. **
Installation
Add this line to your application's Gemfile:
gem 'kawaii-core'
And then execute:
$ bundle
Or install it yourself as:
$ gem install kawaii-core
Running examples
The /examples
directory contains various basic usage examples.
Run the examples using rackup or directly:
$ cd examples
$ rackup -r kawaii modular.ru
Many examples can also be run directly without rackup, e.g.:
$ cd examples
$ ruby -r kawaii hello_world.rb
## Getting started
Kawaii's basic usage is very similar how you'd use Sinatra. You can define route handlers at the file scope. Here's an example:
require 'kawaii'
get '/' do 'Hello, world!' end
Save it to `hello.rb` and start the server like this:
$ rackup -r kawaii hello.rb --port 8088
Then navigate to `http://localhost:8088` to see the greeting.
## Using rackup
To run the app you created in the "Getting started" section above using rackup, create the following `hello.ru` file:
require 'kawaii' require_relative 'hello'
run Kawaii::SingletonApp
`SingletonApp` contains all routes defined at the file scope.
## Defining routes
There are several methods you can use to build your routes, handle passed parameters and so on.
### Supported HTTP methods
The basic way to add a route handler is to invoke a method corresponding to the given HTTP verb, e.g.:
post '/users' do # Some response end
Here, the `post` method corresponds to the `POST` HTTP verb.
Here's a list of supported HTTP verbs:
- get
- post
- put
- patch
- delete
- head
- options
- link
- unlink
- trace
### Wildcard matching
Patterns in route definitions may contain wildcard characters `*` and `?`.
For example `get '/users/?'` matches both `/users/` and `/users` while `get '/users/*'` will match any path starting with '/users/' e.g. '/users/foo/bar'.
### Parameters
Route patterns may contain named parameters, prefixed with a colon. Parameters are accessible through the `params` hash in handler:
get '/users/:id' do params[:id] end
(When requested with `/users/123`, the above route handler will render `"123"`.)
### Regular expressions
Route patterns may contain regular expressions. Example:
get %r/users//users/.* do 'Hello, world' end
### Nested routes
Routes may be nested using the `context` method. Example:
context '/api' do get '/users' do 'Hello' end end
Will above handler will be accessible through `/api/users`.
### Custom matchers
If string patterns and regular expression are not flexible enough, you can create a custom matcher.
A matcher instance responds to `match` method and returns either a `Match` instance or nil if there's no match. See documentation for {Matcher#match} for more details.
### Request object
Handlers can access the `Rack::Request` instance corresponding to the current request:
get '/' do request.host end
### View templates
View templates must currently be stored in `views/` directory of the project using Kawaii. They can be rendered using the `render` method:
get '/' do render('index.html.erb') end
You can set instance variables and use them in the templates.
get '/' do @title = 'Hello, world' render('index.html.erb') end
Let's say `views/index.html.erb` looks like this:
<%= @title %>
In that case, when you visit the page, you'll see **Hello, world**.
Supported templating engines include: ERB, Haml, Liquid, Builder, Kramdown and others. Note that you may need to include the specific gem implementing the given templating engine as inferred from the file name of the template.
## Modular apps
For building more complex applications, you can split them into separate classes, each implementing a subset of functionality (e.g. website and an API).
To create an application, inherit from `Kawaii::Base` and define your routes inside the class.
Let's create `website.rb`:
```ruby
require 'kawaii'
class Website < Kawaii::Base
get '/' do
'Hello, world'
end
end
Now here's how api.rb
may look like:
require 'kawaii'
class API < Kawaii::Base
get '/info' do
'This is some information'
end
end
Let's use the apps in a config.ru
:
require 'kawaii'
require_relative 'website'
require_relative 'api'
map '/' do
run Website
end
map '/api' do
run API
end
Model-view-controller apps
Kawaii supports routing to controllers by either specifying the specific controller + action for a given route or by creating automatic Restful resources (via route
).
Let's suppose we have a controller in hello_world.rb
has typical CRUD methods that mimick Rails controllers:
class HelloWorld < Kawaii::Controller
def index
'Hello, world'
end
end
An in users.rb
:
class Users < Kawaii::Controller
def index
'GET /users'
end
def show
"GET /users/#{params[:id]}"
end
def create
'POST /users'
end
def update
"PATCH /users/#{params[:id]}"
end
def destroy
"DELETE /users/#{params[:id]}"
end
end
Here's how we can define routes (in app.rb
):
require 'kawaii'
require_relative 'hello_world'
require_relative 'users'
get '/', 'hello_world#index' # Explicitly route to `HelloWorld#index` to show the welcome page
route '/users', 'users'
You can run the app directly using ruby
or create config.ru
:
require_relative 'app.rb'
run Kawaii::SingletonApp
Of course, you can
Testing
I recommend using Rack::Test
for testing (see here). Look at specs in spec/
to see how you can use it.
To make a long story short, a class deriving from Kawaii::Base
containing your routes is app
. Let's suppose, your app class is MyApp
, here's how you could test it:
describe MyApp
let(:app) { MyApp }
it 'renders home page' do
get '/'
expect(last_response).to be_ok
end
end
Resources
See /examples
Reference
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/bilus/kawaii.
License
The gem is available as open source under the terms of the MIT License.
TODO
- Hello world app.
- Specs for the app.
- GET routes inside a class deriving from Base.
- Support for running apps without config.ru (ruby -I ./lib examples/hello_world.rb
- Top-level routes.
- Example for top-level routes.
- Nested routes.
- Modular apps (multiple modules via config.ru).
- Matchers.
- Wildcard regex routes, e.g. '/foo/bar/?'.
- Parameter-based routes. Unsupported in 'context'.
- Request object.
- Merge Rack Request params.
- String responses.
- Other HTTP verbs.
- Refactor & create individual files.
- Views (via
render
method in handlers) using Tilt. - Rack route test helpers work.
- API reference.
- Check: References to methods defined in contexts and at class scope.
- Controllers - 'hello_world#index'
- 'route' to controllers (via class name or symbol references).
Controllers - render.
Readme - description and tutorial.
Rubocop-compliant.
Push gem.
Example project using the gem and controllers (with views).
Rack/custom global middleware.
Route-specific middleware.
Custom error handling (intercept exceptions, 404 what else?).
Code review
Known issues
Rubocop
lib/kawaii/routing_methods.rb:46:1: C: Extra blank line detected.
The extra line is necessary for Yard to ignore the comment. Adjust Rubocop settings.