Giter Site home page Giter Site logo

rack-app / rack-app Goto Github PK

View Code? Open in Web Editor NEW
408.0 408.0 20.0 1.84 MB

minimalist framework for building rack applications

License: Apache License 2.0

Ruby 99.98% HTML 0.01% Shell 0.01%
api rack rack-apps ruby ruby-framework web-app web-application-framework web-application-frameworks

rack-app's Introduction

rack-app-logo

rack-app GPT assistant

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:

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 (or just Radix tree). Nodes with a common prefix also share a common parent.

Contributors

Usage

basic

require 'rack/app'

class App < Rack::App

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

end

complex

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.

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

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

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.

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 code of conduct.

License and Copyright

Rack::App is free software released under the Apache License V2 License. The logo was designed by Zsófia Gebauer. It is Copyright © 2015 Adam Luzsi. All Rights Reserved.

rack-app's People

Contributors

adamluzsi avatar blasiusvonszerencsi avatar dependabot[bot] avatar jbmeerkat avatar klebershimabuku avatar readmecritic avatar thefury avatar thesmartnik avatar thesnapdragon avatar thilonel avatar waghanza avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rack-app's Issues

Make project more welcoming by changing the illustrations

I'm really interested in your work, but I can't help but think the big illustration of the woman on your README and homepage makes the project less welcoming to a wide range of potential users and contributors.

Would you by any chance consider removing these illustrations or replacing them with something else? Thank you for your consideration!

Benchmarks update suggestions

A triplet of thoughts:

  1. Since Rack 2.0 requires Ruby 2.2, it would be interesting to see the benchmarks for the updated version.
  2. (Disclamer: I'm Plezi's author) I'm wondering how the framework would bench in comparison to plezi.io.
  3. It would be great to have the benchmark code available to run as a script (allowing each person to test variations on features).

Website Squatted

It looks like the registration for the website you have listed for the project expired and has been taken over.

Listing the middleware so I can see the order.

I ran into a situation when using rack middlewares

I would like to implement

Screenshot 2023-09-13 at 00 46 14

the idea being, when I call

rack-app middlewares

``

I get. list of middleware  in the order they are used.

It would help to solve a problem I am having with middleswares not been in the correct order or specified in the wrong place,

POST request without Content-Length header on WEBrick yields HTTP status code 411

Post handler does not work

Describe the bug

Post handler does not work

To Reproduce
Steps to reproduce the behavior:

class App < Rack::App
  post '/users' do
  end
end
curl -v -X POST localhost:9292/users                                   ?7 13:41:05
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 9292 (#0)
> POST /users HTTP/1.1
> Host: localhost:9292
> User-Agent: curl/7.64.1
> Accept: */*
>
< HTTP/1.1 411 Length Required
< Content-Type: text/html; charset=ISO-8859-1
< Server: WEBrick/1.6.0 (Ruby/2.7.1/2020-03-31)
< Date: Sun, 31 May 2020 10:41:14 GMT
< Content-Length: 303
< Connection: close
<
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
<HTML>
  <HEAD><TITLE>Length Required</TITLE></HEAD>
  <BODY>
    <H1>Length Required</H1>
    WEBrick::HTTPStatus::LengthRequired
    <HR>
    <ADDRESS>
     WEBrick/1.6.0 (Ruby/2.7.1/2020-03-31) at
     localhost:9292
    </ADDRESS>
  </BODY>
</HTML>
* Closing connection 0

Expected behavior

Raise no error ```Length Required``

ruby interpreter

MRI

ruby version
2.7.1
rack-app version
rack-app (7.6.4)
Additional context
Add more examples with other no just GET methods

Namespace bug with numerical + dot formats (ex: /api/v1.0.0)

Hello,

I've noticed an issue with namespace after updating to version 5.11.0 from 5.10.2:

You can actually define this kind of URLs: /api/v1/anything but not this kind anymore: /api/v1.0.0/anything.

The "magical" thing is that even if /api/v1.0.0/anything doesn't work, /api/v1.0/anything works for a reason I don't know.

A sample app with the problem described and technical details is available here: https://github.com/JoWilfrid/rack-app-namespace-bug

Thank you.

Selective Basic Auth

Hey, is there any convenient way to make selective Auth for certain endpoints?

I designed something like this:

class App < Rack::App
  
  def allowed_paths
    ['/v1/insecure_test', '/v1/other_insecure_endpoint']
  end

  def self.call(env)
    unless self.allowed_paths.include? env['REQUEST_PATH']
     middlewares do |b|
        b.use Rack::Auth::Basic, "Restricted Area" do |username, password|
          [username, password] == authenticate
        end
      end
      super
    else
      super
    end
  end

  namespace :v1 do
    get '/secure_test' do
      # some stuff that requires authentication
    end
   
    get '/insecure_test' do
      # some stuff that does't require authentication
    end
 end

end

But there's a drawback in this solution, it tries to authenticate any endpoint whether it was in allowed_paths or not after you visit restricted URL. May be there is a common way for this functionality I have no idea of, or you can suggest some elegant one.

Time to give back!!

@adamluzsi hey hope all is well

https://chat.openai.com/g/g-Coosp4Vb8-rack-app

I think this would be a great addition to the project,

Prompt:

Rack::App is the consummate expert on the rack-app gem, delivering advice with a blend of friendliness, informativeness, and authority. It is dedicated to the rack-app and Rack, avoiding discussions of other frameworks like Sinatra and focusing on minimalistic solutions. Rack::App will confidently advise on the use of extensions and mounts, and when faced with questions beyond its scope, it will acknowledge its limits. This GPT will engage users in a professional yet approachable manner, ensuring communications are clear and helpful, reinforcing its role as a trusted resource in the Ruby community.

unify #params method with the #payload method behaviour

Make #params method behave like the #payload method in terms of parsing behaviours upon validation.

Current behaviour

class T < Rack::App
     validate_params do
        required 'q', :class => Integer
      end
      get '/' do
        params #> { "q" => "1" }
      end
end

# get "/", :params => { "q" => 1 }

Expected behaviour

class T < Rack::App
     validate_params do
        required 'q', :class => Integer
      end
      get '/' do
        params #> { "q" => 1 }
      end
end

# get "/", :params => { "q" => 1 }

param_group

I need an param_group options, like the apipie... for the create and update params for example ;)

Rack::App::FileServer.serve_file gives Errno::EPERM when file served from a shared folder where multiple user keep files like the temp directory.

Calling #serve_file to with a generated tempfile might fail with a permission error when not all files in the temp directory are readable.

[2020-12-12 13:08:38] ERROR Errno::EPERM: Operation not permitted - /var/folders/p5/bjvqf64509z5k5kyhkmyknch0000gn/T/com.apple.iCal/TemporaryItems

The temp file in case was:
/var/folders/p5/bjvqf64509z5k5kyhkmyknch0000gn/T/points20201212-56050-1p0873w.csv

Reproduce:

tmp = Tempfile.new(%w[points .csv])
puts ">>> #{tmp.path} <<<"

# having or creating any non readable file/dir in the /var/folders/p5/bjvqf64509z5k5kyhkmyknch0000gn/T directory now will fail the serve_file call
# I'm to lazy now, in my case it was a calendar file showing up there,

serve_file tmp.path

The reason for this is that serve_file starts a file server for ALL files in the directory of the given path. With resulting eperm in case any non readable file is there.

Besides that, this also is a security bug, exposing the whole directory instead of just the file.

You can read the globbing action in file_server.rb:6:

[2020-12-12 13:08:38] ERROR Errno::EPERM: Operation not permitted - /var/folders/p5/bjvqf64509z5k5kyhkmyknch0000gn/T/com.apple.iCal/TemporaryItems
        /Users/crux/.rvm/gems/ruby-2.7.1/gems/rack-app-4.0.1/lib/rack/app/file_server.rb:6:in `glob'
        /Users/crux/.rvm/gems/ruby-2.7.1/gems/rack-app-4.0.1/lib/rack/app/file_server.rb:6:in `initialize'
        /Users/crux/.rvm/gems/ruby-2.7.1/gems/rack-app-4.0.1/lib/rack/app/file_server.rb:24:in `new'
        /Users/crux/.rvm/gems/ruby-2.7.1/gems/rack-app-4.0.1/lib/rack/app/file_server.rb:24:in `serve_file'
        /Users/crux/.rvm/gems/ruby-2.7.1/gems/rack-app-4.0.1/lib/rack/app/instance_methods/upload.rb:4:in `serve_file'

ruby version
rack-app version

.rvm/gems/ruby-2.7.1/gems/rack-app-4.0.1/lib/rack/app/file_server.rb

Markdown documentation based on registered endpoints

Create CLI command that able to output endpoint documentation based on registered endpoints

  • Description
  • request method
  • request path
  • query parameters and they:
    • desc
    • type
    • example

for MVP this should be enough.

Make `request.params` behave similarly as the `params` method

Dear Contributors,

For an apparent reference on the Rack's request object, you can view it here.

This feature request was prompted by the following feedback.

Currently, the request object available within the endpoint block scope is an instance of Rack::Request.

Rack::Request in Ruby's Rack library provides a foundational interface for incoming HTTP requests, encapsulating the raw HTTP data in an intuitive, object-oriented format.

Frameworks such as rack-app, Sinatra, or Rails introduce a more intricate layer with path parameters, rooted in the RESTful API design concept that transforms URL path segments into parameters.

While Rack::Request manages raw HTTP data without deducing the URL structure or routing, higher-level frameworks built on Rack introduce path parameters.

A discrepancy arises when params and request.params return different values.

Though our preference for the minimalist approach using the core Rack::Request kept things uncomplicated, it appears to have led to an unclear API concerning parameters in this context.

To address this, we plan to roll out a Rack::App::Request. This will align the parameter accessors with the endpoint scope:

  • path_segments_params: Parameters present solely in your path segments.
  • query_string_params: Parameters found only in your query string.
  • validated_params: Parameters that have passed your validation, ensuring protection against hash key-value-based injections.
  • params: This will return:
    • validated_params if validation is specified.
    • Otherwise, it will consolidate all parameter types into a hash map for retrieval.

Thank you for your continued collaboration and understanding.

Puma error

I get this error when running this simple app in Puma 3.5.2 and Rack 1.5.5:

Puma caught this error: uninitialized constant Rack::PATH_INFO
Did you mean?  Pathname (NameError)
/usr/local/lib/ruby/gems/2.3.0/gems/rack-app-5.2.0/lib/rack/app/request_configurator.rb:13:in `path_info'
/usr/local/lib/ruby/gems/2.3.0/gems/rack-app-5.2.0/lib/rack/app/request_configurator.rb:6:in `configure'
/usr/local/lib/ruby/gems/2.3.0/gems/rack-app-5.2.0/lib/rack/app/singleton_methods/rack_interface.rb:6:in `call'
/usr/local/lib/ruby/gems/2.3.0/gems/rack-1.5.5/lib/rack/builder.rb:138:in `call'
/usr/local/lib/ruby/gems/2.3.0/gems/rack-1.5.5/lib/rack/urlmap.rb:65:in `block in call'
/usr/local/lib/ruby/gems/2.3.0/gems/rack-1.5.5/lib/rack/urlmap.rb:50:in `each'
/usr/local/lib/ruby/gems/2.3.0/gems/rack-1.5.5/lib/rack/urlmap.rb:50:in `call'
/usr/local/lib/ruby/gems/2.3.0/gems/puma-3.5.2/lib/puma/configuration.rb:225:in `call'
/usr/local/lib/ruby/gems/2.3.0/gems/puma-3.5.2/lib/puma/server.rb:569:in `handle_request'
/usr/local/lib/ruby/gems/2.3.0/gems/puma-3.5.2/lib/puma/server.rb:406:in `process_client'
/usr/local/lib/ruby/gems/2.3.0/gems/puma-3.5.2/lib/puma/server.rb:271:in `block in run'
/usr/local/lib/ruby/gems/2.3.0/gems/puma-3.5.2/lib/puma/thread_pool.rb:116:in `block in spawn_thread'

It seems the ::Rack::PATH_INFO constants is not defined in Rack.
Am i missing something?

Circular dependency bug while testing rack-app application

Hello, it's me ♬ (again)

As I'm writing tests for all my rack-app APIs I'm facing a (non-blocking) bug caused by a circular dependency.
It looks like, in a test context, it creates a infinite loop between 2 inclusions: rack/app requires rack/app/version which requires rack/app.

The code in lib/rack/app/version.rb is as following:

require 'rack/app'
Rack::App::VERSION = File.read(File.join(File.dirname(__FILE__), '..', '..', '..', 'VERSION')).strip

You can find a project that reproduced the bug here

It seems to occur around this line:

RACK_APP = Rack::Builder.parse_file('config.ru').first

The test library used is minitest without rspec.

Hope there is enough details. Feel free to ask for any missing information.

PS: thank you again for this project ;)

params is empty {} when send form to post "/hello"

Describe the bug
A clear and concise description of what the bug is.

To Reproduce
Steps to reproduce the behavior:

  1. test.rb
require "rack/app"

class App < Rack::App
  desc "some hello endpoint"
  get "/hello" do
    '<!doctype html><html><head></head><body><form  action="/hello" method="post" ><input name="username" ><button>Send</button></form></body></html>'
  end

  desc "post hello endpoint"
  post "/hello" do
    params["username"]
  end
end
  1. config.ru
require './test'
run App

rackup
3. visit http://localhost:9292/hello
fill form
4. click send button
post params is empty {}

Expected behavior
A clear and concise description of what you expected to happen.

ruby interpreter
ruby interpreter implementation like Mruby, Jruby, ...

ruby version
ruby 2.6.6p146
rack-app version

Additional context
Add any other context about the problem here.

What is the best way to bundle views in an extension?

Rack::App::Extension.register(:example) do
  get 'greeting' do
      render 'greeting.html.erb'
  end
end

Given the example extension above, I want to package the is extension in a gem.
what would be the best way to bundle the greeting.html.erb with extension?

I have looked at the documentation , worker and sequel extensions for inspiration but I have not found an example which bundles views.

I am thinking of adding the views to the gem and using hooks to copy them into place, but this does not sound very minimalistic.

@adamluzsi What would you suggest?

Application initialization appears to be quadratic in the number of routes

Rack::App appears to have O(1) routing, at least for static routes (as one would expect from using a hash table), but it also appears that application initialization is quadratic in the number of routes. Here are rough times in seconds for initialization with the following number of routes:

10: 0.418303426
15: 0.419373569
100: 0.530071716
225: 0.936073043
1000: 10.068363325
3375: 110.984736365

Example code:

require 'rack/app'
class App < Rack::App
  1000.times do |i|
    get "/#{i.to_s}" do
    end
  end
end

Is this expected behavior?

Refine Hook Execution Scope to Match Defined Context

Based on @vidtreonou observation, the scope where the 'before'/'after' block executes might be misaligned.

Let's break down the root of the issue that @vidtreonou identified.

The Issue:
The 'before' block is set to execute before an endpoint being accessed and operates within the scope of that endpoint. The scenario you pinpointed is unique: the 'before' block utilizes an instance method from the class where it's defined. However, during execution, the block's scope shifted to the mounted application.

class A < Rack::App
  get "/" do
    "Hello, world!"
  end
end

class B < Rack::App
  before { my_instance_method }

  def my_instance_method()
  end
  
  mount A, to: "/x" 
end

run B

# Accessing /x/ results in a no-method error 

My Suggested Solution:
I propose that the 'before' block should recognize the class in which it's established. Subsequently, the hook's execution should be adjusted to remain within the scope of the class where it was defined rather than switching to the class of the called endpoint.

remove application configuration need during runtime

refactor the code base, so application instances are not required to be built during runtime.

Proposal

use the first call(env) as the trigger point to build the application, and make sure that mounting and other routing-related actions will remove the built application instance.

add support for configuration passing to mounted applications

Why this is matter ?

With this there would be option to create applications that doesn't include hardcoded models.
If the application it self only depend on a object that comes from mount configuration, this would allow the developer to define flexible reusable applications that could be used even with different Models.

Example

class T < Rack::App

  get '/first' do
    # this for example will define that the user model should respond to first method
    mount_options[:user_model].first
  end

end

Concerns about different implementations

mount_options should only be available during on request call, else it would support bad singleton pattern practices such as class manipulation based on mount options. In a single case scenario it would work, but would not be generic and reusable. And the singleton pattern would ruin it's testability! But if it would be instance method, than it would enforce on runtime instance manipulation maximum, but nothing else in a bigger scope.
But for this, the ability to test with the created application tests is pretty required.

Testability

The created test for the app that depends on the mount options also should be reusable.
This is still TBD

Outdated Sinatra fails to boot

Given

require 'rack/app'
require_relative 'sinatra'
require_relative "./dlr/config/environment" # small rails app


class App < Rack::App

  mount_rack_based_application Dlr::Application, to: "/rails" 
  mount_rack_based_application SinatraApp, to: "/sinatra"

  Rails.application.load_server
  
  desc 'health check endpoint'
  get '/' do
    'OK'
  end

  get '/hello' do
    'Hello World'
  end

end

when I run

bundle exec rackup config.ru

I get the following Error

Screenshot 2023-10-04 at 09 21 07

on investigation in noticed that when I bundle it is rolling back to version 7 of rack-app, admiteldly I am not sure how relevant it is.

Screenshot 2023-10-04 at 09 12 37

here is a zip of the project.

broken-rack-app.zip

Any help would be hugely appreciated.

RSpec warnings

Cosmetic warnings, but still they show up when running RSpec on my project with warnings enabled:

/home/mic/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rack-app-7.6.1/lib/rack/app/payload/parser/builder/formats.rb:79: warning: mismatched indentations at 'end' with 'else' at 75
/home/mic/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rack-app-7.6.1/lib/rack/app/streamer/scheduler/null.rb:7: warning: mismatched indentations at 'end' with 'def' at 5

Error handler for mounted app

Error handlers work fine for exception raised inside the app.

But when an exception is raised in a mounted app, the error handler of the parent app is not called.

Is there a way to get this behaviour, or is it a feature request?

Unexpected behavior of request param parsing

Hi, we've found bug in framework behaviour.
When you do request with FQDN inside URL path, framework silently cuts last domain part.
F.e.
GET http://mysite.com/api/example.com will result
to params["fqdn"] = "example" and expected is params["fqdn"] = "example.com".

Bug appears only when domain name is the last param. So for example:
F.e.
GET http://mysite.com/api/example.com/12345 will result
to params["fqdn"] = "example.com" and expected is params["fqdn"] = "example.com".

How to serve static assets with Rack::App?

I am trying to make Rack::App serve static files from the folder public/ (like possible with Sinatra using set :public_folder, 'public').

Is this supported out of the box? If not, how to do it in the simplest way?

Mounted application is not reloaded by Rack::Reloader

Describe the bug
When a modification is made in a mounted application code, changes are not reloaded and rack-app serves the not-modified app.

To Reproduce
Simple rack-app:

require 'rack-app'

puts 'Identity App file loaded'

module Identity
  class IdentityApp < Rack::App
    get '/signup_token' do
      { token: 'Ok token' }.to_json
    end
  end
end

mounted in my main app:

mount Identity::IdentityApp, to: '/v3/identity'

Expected behavior
Now, I change the signup_token response (even doing a syntax error) and the response to a request is not modified until I restart the main rack-app.

The file itself is reloaded by Rack::Reloader since the puts statement shows up in the console.

ruby interpreter
MRI

ruby version
2.7.1

rack-app version
7.6.3

Parsing form data

Is there a nice way to get parsed values of form data? I can do

class App < RackApp
  post '/' do
    parsed_form_data = request.POST
    # ...
  end
end

but request.POST seems not to be very rack-app-ish. In standard rack the parsed form data is merged in params but I think a different method like parsed_form_data would be a better solution.

It would also be nice to have validations for form data, something like

desc 'example'
validate_form_data do
  required 'description', class: String, desc: 'example description'
end
post '/example' do
  desc = parsed_form_data['description']
  # ...
end

Did I miss something or is such functionality not (yet) implemented?

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.