URI params serializable

I have been building more clients lately and I am curious. There seems like there would be a good use for something like JSON::Serializable for URI::Params. What do people normally use for this and would this be a good addition to the stdlib?

What benefits are you imagining for a URI::Params::Serializable mixin? The main benefit I’ve noticed with constructs like JSON::Serializable and similar constructs for other similar serialization formats is that, since the data structures are nested, you can reuse types in a lot of different places. For example, Stripe’s API embeds customer and payment_method objects in a lot of different responses. Since URI::Params doesn’t allow nesting, I don’t know what the benefits would be.

Though, to be fair, Stripe’s API is a pretty interesting example for me to use here since their API receives form-encoded data and emits JSON.

I usually use them as I would a Hash(String, String | Array(String)). In place of explicit type casting, params[key]? returns the string (if the key exists) and params.fetch_all(key) returns all values for that key.

For example, let’s say you’re publishing a post:

params = r.form_params
title = params["title"]?
body = params["body"]?

# Check to see that the params were provided, since the
# PostQuery#create method requires them to be strings
if title && body && valid_authenticity_token?(params, session)
  case result = PostQuery.new.create(title, body)
  in Validations::Success(Post)
    response.redirect "/posts/#{result.object.id}"
  in Validations::Failure
    errors = result.errors
    render "posts/errors"
    render "posts/form"
  end
else # Probably didn't come in via the form
  response.status = :bad_request
end

And to build them to send to a remote server:

params = URI::Params{
  "foo" => foo,
  "bar" => bar,
}

response = http.post("/path/to/endpoint", body: params.to_s)

I think mappings to Crystal types are great for any serialization format. Even arguably simple ones.
It’s easy to use and ensures type safety.

A good role model for serialization implementations is Rust’s serde framework. And it has a plugin for URI params as well: serde_qs.