Rewriting to Haskell–Standing on the shoulders of Rails
Tags: functional, haskell, servant
Published: 2020-03-30 08:32:57

You can keep reading here or [jump to my blog](https://odone.io/posts/2020-03-30-rails.html) to get the full experience, including the wonderful pink, blue and white palette.

---

This is part of a series:

- [Rewriting to Haskell–Intro](https://odone.io/posts/2020-02-26-rewriting-haskell-intro.html)
- [Rewriting to Haskell–Project Setup](https://odone.io/posts/2020-03-03-rewriting-haskell-setup.html)
- [Rewriting to Haskell–Deployment](https://odone.io/posts/2020-03-14-rewriting-haskell-server.html)
- [Rewriting to Haskell–Automatic Formatting](https://odone.io/posts/2020-03-19-rewriting-haskell-formatting.html)
- [Rewriting to Haskell–Configuration](https://odone.io/posts/2020-03-23-rewriting-haskell-configuration.html)

---

In the [intro](https://odone.io/posts/2020-02-26-rewriting-haskell-intro.html) we mentioned we wanted to work in "small valuable iterations". In fact, we know from experience scope creep is a thing and we want to keep our laser focus on the goal. Well, with the exception of the usual Oxford Discussion™ with [Alex](https://www.linkedin.com/in/alexander-suminski/) on functional code design.

When rewriting part of a mature codebase, a good way of breaking down work is to reuse what's already there. Turns out that with some outside-the-box thinking, we could make Rails our handrail.

We decided to start by rewriting one endpoint, the search one. As a matter of fact, in Stream, posts and comments can be found by submitting a query to the backend.

Rails takes care of authentication and, as said above, we wanted to keep the scope of the iteration small. Thus, we decided to leave it be and just delegate to Servant the search:

```diff
diff --git a/app/controllers/api/v1/search_controller.rb b/app/controllers/api/v1/search_controller.rb
     class SearchController< Api::V1::ApiController
       def index
-        render json: posts, root: 'posts', status: :ok
+        q = { query: query, channel: channel, quantity: quantity, last_id: last_id, comments: comments }.compact
+        response = self.class.get("http://localhost:8080/servant/search", query: q)
+        render json: response, status: :ok
       end
```

Furthermore, this enables us to reuse all the RSpec tests we have! Though we needed to change one line. In fact, to wipe the database we were running each spec inside a database transaction.

Since now Rails runs in one process and Servant in another, using a transaction would shadow data to the latter. This is because, until a transaction is committed, records are not available outside of it. Therefore, instead of cleaning the database with transactions, we will use truncation:

```diff
diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb
   config.before(:each) do
-    DatabaseCleaner.strategy = :transaction
+    DatabaseCleaner.strategy = :truncation
   end
```

Also, in CI now we need to spin up the Servant application before running RSpec:

```bash
- run:
    command: DATABASE=stream_test stack --no-terminal exec haskell-exe
    background: true
```

Et voilà, now we don't have to write tests in Haskell. We will, we will but we bought ourselves some time at least 😎

---

Get the latest content via email from me personally. Reply with your thoughts. Let's learn from each other. Subscribe to my [PinkLetter](https://odone.io#newsletter)!