Announcing rom-http

Today we have another exciting release for you - rom-http 0.8.0. This is the biggest release of this adapter so far, as it's been integrated fully with the core APIs. This means you can now use rom-http to build HTTP client libraries, and leverage powerful auto-mapping capabilities of rom-rb.

This adapter works in the same way as any other rom-rb adapter. You configure a gateway, register relations with schemas and voilĂ  - you can talk to remote HTTP APIs now. Let's see how this looks in actual code.

GitHub API Example

To connect to a remote HTTP API you simply provide the uri and which response/request handlers should be used, in this case we will set :json:

config = ROM::Configuration.new(:http, uri: "https://api.github.com", handlers: :json)

Now we can define a relation class. For the purpose of this example we'll use a relation that will query /orgs end-point:

module GitHub
  module Resources
    class Organizations < ROM::Relations[:http]
      schema(:orgs) do
        attribute :id, Types::Integer
        attribute :name, Types::String
        attribute :created_at, Types::JSON::Time
        attribute :updated_at, Types::JSON::Time
      end

      def by_name(name)
        append_path(name)
      end
    end
  end
end

config.register_relation(GitHub::Resources::Organizations)

rom = ROM.container(config)

We only defined a sub-set of all the attributes, mappers will reject extra keys for us and give us back simpler data structures. Notice the by_name view in this class - it appends organization name to the base path. For example org/rom-rb is the path we want to use to find an organization named rom-rb.

Relation#append_path is just one of the many convenient methods that are available, that will help you in constructing HTTP queries. Refer to API documentation for more information.

Let's see this in action now:

orgs = rom.relations[:orgs]

# Plain hashes by default unless you set `auto_struct true` globally
orgs.by_name('rom-rb').one
# {:id=>4589832, :name=>"rom-rb", :created_at=>2013-06-01 22:03:54 UTC, :updated_at=>2019-04-03 14:36:48 UTC}

# Auto-structs on demand
orgs.with(auto_struct: true).by_name('rom-rb').one
# #<ROM::Struct::Org id=4589832 name="rom-rb" created_at=2013-06-01 22:03:54 UTC updated_at=2019-04-03 14:36:48 UTC>

Sweet. Data automatically converted to the exact format that we wanted to have, with unspecified keys rejected and attribute values coerced to configured types.

Release Information

For more information refer to the CHANGELOG.

Give this adapter a try and tell us what you think!


rom 5.0.0 and rom-sql 3.0.0 released

We're happy to announce the release of rom 5.0.0 and rom-sql 3.0.0. Core libraries have been upgraded to work with dry-types 1.0.0 and as a result, schema types can now benefit from all the new dry-types features. Many significant improvements have been introduced in rom-sql, let's take a look at some of the new features.

Support for arbitrary join conditions

It is now possible to set arbitrary join conditions via new DSL:

users.join(tasks) { |users:, tasks:|
  tasks[:user_id].is(users[:id]) & users[:name].is('John')
}

This will produce the following SQL:

SELECT "users"."id", "users"."name"
FROM "users"
INNER JOIN "tasks" ON (("tasks"."user_id" = "users"."id") AND ("users"."name" = 'John'))
ORDER BY "users"."id"

Support for CASE statements

We've also made it simple to construct CASE statements, using the following DSL:

users.select_append {
  id.case(1 => string('one'), else: string('something else')).as(:one_or_else)
}

This will produce the following SQL:

SELECT
  "users"."id",
  "users"."name",
  (CASE "users"."id" WHEN 1 THEN 'one' ELSE 'something else' END) AS "one_or_else"
FROM "users"
ORDER BY "users"."id"

Support for exists in Projection DSL

Support for Relation#exists was added in 2.0.0, now it is also available within the Projection DSL. Here's an example:

users.select_append { |posts: |
  exists(posts.where(posts[:user_id] => id)).as(:has_posts)
}

This will produce the following SQL:

SELECT
  "users"."id",
  "users"."name",
  (EXISTS (SELECT "tasks"."id", "tasks"."user_id", "tasks"."title" FROM "tasks" WHERE ("tasks"."user_id" = "users"."id") ORDER BY "tasks"."id")) AS "has_tasks"
FROM "users"
ORDER BY "users"."id"

Improved pluck support

You can now select more than one attribute when using Relation#pluck:

users.pluck(:id, :name)
# [[1, "Jane"], [2, "Joe"], [3, "Jane"], [4, "John"]]

What's next?

Originally we had an ambitious roadmap for 5.0.0 release, but its scope was simplified so that we could ship it faster, otherwise people would be blocked with upgrading for too long. This means that everything else that didn't get into 5.0.0 will be either implemented in 5.x series, or 6.0.0.

You can also expect new releases of rom-elasticsearch, rom-http and rom-yaml adapters soon.

Release information and upgrading

This is a major release with breaking changes. Please refer to the upgrade guide for more information. As part of 5.0.0, following gems have been released:

If you're having problems with the upgrade, please ask questions on discussion forum or our community chat.


  • 1 of 9