如何实现响应GET /time接口的极简Rack时间格式化应用?
Building a Minimalist Rack App for /time with Custom Formatting
Got it, let's walk through creating this Rack app step by step. I'll break down the logic and code so it's easy to follow and adapt.
Step 1: Recap the Core Requirements
First, let's make sure we cover all your needs clearly:
- Respond only to
GET /timerequests - Accept a
formatquery parameter with comma-separated values (e.g.,year,month,day, URL-encoded asyear%2Cmonth%2Cday) - Return plain-text time matching the requested format order
- Throw a clear error if any unknown format values are provided
- Set the correct
Content-Type: text/plainheader for all responses
Step 2: Write the Rack App Code
We'll use a Ruby class for this (it's more organized than a lambda for handling validation and formatting logic). Save this as config.ru (Rack's default configuration file):
require 'rack' require 'cgi' class TimeFormatterApp # Map user-friendly format names to Ruby's strftime codes SUPPORTED_FORMATS = { 'year' => '%Y', 'month' => '%m', 'day' => '%d', 'hour' => '%H', 'minute' => '%M', 'second' => '%S' }.freeze def call(env) request = Rack::Request.new(env) # Handle non-matching routes/methods first unless request.path == '/time' && request.get? return [404, {'Content-Type' => 'text/plain'}, ['404 Not Found']] end # Check for missing format parameter format_param = request.params['format'] unless format_param return [400, {'Content-Type' => 'text/plain'}, ['Error: Missing "format" query parameter']] end # Decode URL-encoded commas and split into individual format parts requested_formats = CGI.unescape(format_param).split(',') # Validate all requested formats invalid_formats = requested_formats.reject { |format| SUPPORTED_FORMATS.key?(format) } unless invalid_formats.empty? error_msg = "Error: Unsupported format(s): #{invalid_formats.join(', ')}" return [400, {'Content-Type' => 'text/plain'}, [error_msg]] end # Build the time format string and generate the output time_format = requested_formats.map { |f| SUPPORTED_FORMATS[f] }.join('-') # Use Time.at(0) if you want the epoch example (1970-01-01) instead of current time formatted_time = Time.now.strftime(time_format) # Return successful response [200, {'Content-Type' => 'text/plain'}, [formatted_time]] end end run TimeFormatterApp.new
Step 3: Break Down the Logic
Let's unpack what each part does:
- SUPPORTED_FORMATS: A frozen hash that maps human-readable format names to Ruby's
strftimecodes—this makes it trivial to add/remove supported formats later. - call method: The mandatory Rack interface; every Rack app must respond to
callwith an environment hash, returning a [status code, headers, body] array. - Route/Method Validation: We first check if the request is for
/timeand uses GET. If not, we return a 404. - Format Parameter Handling: We decode URL-encoded commas (since
%2Cis the URL escape for,) and split the parameter into individual format parts. - Invalid Format Check: We filter out any formats that aren't in our supported list. If there are invalid ones, we return a 400 error with a specific message.
- Time Formatting: We build the
strftimestring by mapping each requested format to its code, join with-, and format the current time (or epoch time, if you swapTime.nowforTime.at(0)).
Step 4: Test the App
First, install Rack if you haven't already:
gem install rack
Run the app with:
rackup config.ru
Now test these scenarios:
- Valid request:
GET http://localhost:9292/time?format=year%2Cmonth%2Cdayreturns something like2024-05-20 - Invalid format:
GET http://localhost:9292/time?format=year%2CfooreturnsError: Unsupported format(s): foo - Missing parameter:
GET http://localhost:9292/timereturnsError: Missing "format" query parameter - Wrong route:
GET http://localhost:9292/fooreturns404 Not Found
内容的提问来源于stack exchange,提问作者Danil Panshin
相关产品推荐
相关产品推荐

