htmx on Sinatra

—interactive web pages with hypermedia

Part 5: Personalization with GET

When we have captured some form input data, and want to use it on a different page, our first impulse is to send this data along as local variables while redirecting to the new URL; someting like this:

get '/' do
  erb :'index'
end

post '/' do
  # NB! Cannot do this:
  redirect '/thank-you', :locals => { :name => params[:name] }
end

get '/thank-you' do
  # Try referencing the `name` variable in the template:
  erb :"thank-you"
end

This, however, is not going to work.

HTTP is a stateless protocol. Requests don't share information; any data exhanged between client and server is not available to subsequent (or previous) requests. Here, that last GET request has no way of accessing the local variable(s) present in the POST request that's doing the redirect.

This means that we need to pass this information from one request to the next by including it in the URL. First we construct the URL, then redirect to it:

get '/' do
  erb :'index'
end

post '/' do
  redirect "/thank-you/#{params[:name]}"
end

get '/thank-you/:name' do
  erb :"thank-you", :locals => { :name => params[:name] }
end

This also means that we need modify the route for our "thank you" page, by appending a wildcard that can hold the value of the name parameter.

Now this GET request can fetch the name from the URL, and display it in the body of the response:

<h2 class="no-margin">Thank you, <%= name %>!</h2>

(Here's the complete thank-you template).

Notice that in order to make this interaction dynamic, we needed to modify the information architecture of our app. We went from a "thank you" page that does not specify a recipient to one that does — by modifying the last segment of the URL:

http://localhost:9292/thank-you/Alice

This is what REST is about; because HTTP is a stateless protocol, we must use URL layout to describe resources. The HTTP verbs then define the actions that can be performed on those resources.