Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/rack-app/rack-app

minimalist framework for building rack applications
https://github.com/rack-app/rack-app

api rack rack-apps ruby ruby-framework web-app web-application-framework web-application-frameworks

Last synced: 11 days ago
JSON representation

minimalist framework for building rack applications

Awesome Lists containing this project

README

        

# [Rack::App](https://github.com/rack-app/rack-app)

![rack-app-logo](/assets/rack-app-logo.png)

[rack-app GPT assistant](https://chat.openai.com/g/g-DOKIpY8aq-rack-app)

`rack-app` is a minimalist web framework that focuses on simplicity and maintainability.
The framework is meant to be used by seasoned web developers.

`rack-app` focus on keeping the dependencies as little as possible,
while allowing writing functional and minimalist rack-based applications,
that will do nothing more than what you defined.

The routing uses a prefix tree,
thus adding a large number of API endpoints won't affect the routing lookup time.

It was inspirited by `Sinatra`, `grape`, and `rack`.
It's used in production, powering back-end APIs running on the public cloud.

## Development Status

The framework is considered stable.
I don't have the plan to feature creep the framework without real-life use-cases,
since most of the custom edge cases can be resolved with composition.

The next time it will receive further updates,
when rack provides a finalized support for http2.

If you have an issue, I weekly check the issues tab,
answer and reply, or implement a fix for it.

Since the framework's only dependency is the `rack` gem,
I don't have to update the codebase too often.

Cheers and Happy Coding!

## Installation

Add this line to your application's Gemfile:

```ruby
gem 'rack-app'
```

And then execute:

$ bundle

Or install it yourself as:

$ gem install rack-app

## Is it Production ready?

Yes, it's already powering Heroku hosted micro-services.

## Principles

* Keep It Simple
* No Code bloat
* No on run time processing, or keep at the bare minimum
* Fully BDD (Behaviour Driven Design)
* built-in test module to ease the development with easy to use tests
* Easy to Learn
* rack-app use well known and easy to understand conventions, such as sinatra like DSL
* Principle Of Least Surprise
* Modular design
* the Only dependency is rack, nothing more
* Open development
* Try to create Examples for every feature

## Features

* Easy to understand syntax
* module method level endpoint definition inspirited heavily by the Sinatra DSL
* unified error handling
* syntax sugar for default header definitions
* namespaces for endpoint request path declarations so it can be dry and unified
* no Class method bloat, so you can enjoy pure ruby without any surprises
* App mounting so you can create separated controllers for different task
* Streaming
* O(log(n)) lookup routing
* allows as many endpoint registrations to you as you want, without impact on route lookup speed
* only basic sets for instance method level for the must need tools, such as params, payload
* Simple to use class level response serializer
* so you can choose what type of serialization you want without any enforced convention
* static file serving so you can mount even filesystem-based endpoints too
* built-in testing module so your app can be easily written with BDD approach
* made with minimalism in mind so your app can't rely on the framework when you implement business logic
* if you need something, you should implement it without any dependency on a web framework, rack-app only mean to be to provide you with easy to use interface to the web layer, nothing less and nothing more
* per endpoint middleware definitions
* you can define middleware stack before endpoints and it will only apply to them, similar like protected method workflow
* File Upload and file download efficiently and elegantly with minimal memory consuming
* note that this is not only memory friendly way pure rack solution, but also 2x faster than the usual solution which includes buffering in memory
* params validation with ease

## Under the hood

rack-app's router relies on a tree structure which makes heavy use of *common prefixes*,
it is basically a *compact* [*prefix tree*](https://en.wikipedia.org/wiki/Trie) (or just [*Radix tree*](https://en.wikipedia.org/wiki/Radix_tree)).
Nodes with a common prefix also share a common parent.

## Contributors

* **[Daniel Nagy](https://github.com/thilonel)**

* Serializer MVP implementation

* **[Daniel Szpisjak](https://github.com/felin-arch)**

* Pimp up the website descriptions

* **[Jeremy Evans](https://github.com/jeremyevans)**

* suggestion for application stand up speed optimization

* **[David Bush](https://github.com/disavowd)**

* [wrote an awesome article](https://www.sitepoint.com/rack-app-a-performant-and-pragmatic-web-microframework/) about the project

* **[TheSmartnik](https://github.com/TheSmartnik)**

* Clarify examples in the documentation

## [Contributing](CONTRIBUTING.md)

## Usage

#### basic

```ruby

require 'rack/app'

class App < Rack::App

desc 'some hello endpoint'
get '/hello' do
'Hello World!'
end

end

```

#### complex

```ruby

require 'rack/app'

class App < Rack::App

mount SomeAppClass

headers 'Access-Control-Allow-Origin' => '*',
'Access-Control-Expose-Headers' => 'X-My-Custom-Header, X-Another-Custom-Header'

serializer do |object|
object.to_s
end

desc 'some hello endpoint'
validate_params do
required 'words', :class => Array, :of => String, :desc => 'some word', :example => ['pug']
optional 'word', :class => String, :desc => 'one word', :example => 'pug'
optional 'boolean', :class => :boolean, :desc => 'boolean value', :example => true
end
get '/hello' do
puts(params['words'])

'Hello World!'
end

namespace '/users' do

desc 'some restful endpoint'
get '/:user_id' do
response.status = 201
params['user_id'] #=> restful parameter :user_id
say #=> "hello world!"
end

end

desc 'some endpoint that has error and will be rescued'
get '/make_error' do
raise(StandardError,'error block rescued')
end

def say
"hello #{params['user_id']}!"
end

error StandardError, NoMethodError do |ex|
{:error=>ex.message}
end

root '/hello'

get '/stream' do
stream do |out|
out << 'data row'
end
end

end

```

you can access Rack::Request with the request method and
Rack::Response as a response method.

By default, if you don't write anything to the response 'body' the endpoint block logic return will be used

### Frontend Example

if you don't mind extending your dependency list then you can use the front_end extension for creating template-based web applications.

```ruby
require 'rack/app'
require 'rack/app/front_end' # You need to add `gem 'rack-app-front_end'` to your Gemfile

class App < Rack::App

apply_extensions :front_end

helpers do

def method_that_can_be_used_in_template
'hello world!'
end

end

# use ./app/layout.html.erb as layout, this is optionable
layout 'layout.html.erb'

# at '/' the endpoint will serve (render)
# the ./app/index.html content as response body and wrap around with layout if the layout is given
get '/' do
render 'index.html'
end

end
```

this example expects an "app" folder next to the "app.rb" file that included templates being used such as layout.html.erb and index.html.

## Testing

for testing use rack/test or the bundled testing module for writing unit test for your rack application

```ruby

require 'spec_helper'
require 'rack/app/test'

describe App do

include Rack::App::Test

rack_app described_class

describe '/hello' do
# example for params and headers and payload use
subject { get(url: '/hello', params: {'dog' => 'meat'}, headers: {'X-Cat' => 'fur'}, payload: 'some string') }

it { expect(subject.status).to eq 200 }

it { expect(subject.body).to eq "Hello World!" }
end

describe '/users/:user_id' do
# restful endpoint example
subject { get(url: '/users/1234') }

it { expect(subject.body).to eq 'hello 1234!'}

it { expect(subject.status).to eq 201 }

end

describe '/make_error' do
# error handled example
subject { get(url: '/make_error') }

it { expect(subject.body).to eq '{:error=>"error block rescued"}' }
end

end

```

## Example Apps To start with

* [Official website How To examples](https://github.com/rack-app/rack-app/wiki)

* [Rack::App Team Github repositories](https://github.com/rack-app)

* [Basic](https://github.com/rack-app/rack-app-example-basic)
* bare-bone simple example app

* [Escher Authorized Api](https://github.com/rack-app/rack-app-example-escher)
* complex authorization for corporal level API use

## Development

After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).

## Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/rack-app/rack-app This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.

## License and Copyright

Rack::App is free software released under the [Apache License V2](https://opensource.org/licenses/Apache-2.0) License.
The logo was designed by Zsófia Gebauer. It is Copyright © 2015 Adam Luzsi. All Rights Reserved.