Who Needs Lodash When You Have Elixir?

Written by Pete Corey on Apr 17, 2017.

Before adventuring into the land of Elixir, I used Javascript day in and day out for both front-end and back-end development. Javascript’s (lack of) standard libraries forced me to rely heavily on third-party tools and libraries such as Underscore and Lodash.

I became very proficient at working with these tools, and after initially starting with Elixir, I felt very clumsy with the new language. I wasn’t able to accomplish the things I could easily and quickly do with Javascript and Lodash.

Over the past few months, I’ve become much more comfortable with the language, and I’ve realized that Elixir’s standard library outclasses Lodash in nearly every way.

Let’s dig into the two and see how we would translate the Lodash-isms we know and love into Elixir code.

The Usual Suspects

For many functions in Lodash, there’s an obvious mapping to an equivalent function in Elixir’s standard library.

For example, the usual suspects like _.map, _.reduce, _.find, and _.filter all have equivalent functions in Elixir’s Enum module:


_.map([1, 2, 3], n => n + 1)  // Enum.map([1, 2, 3], &(&1 + 1))

_.reduce([1, 2, 3], (s, n) => s + n)  // Enum.reduce([1, 2, 3], &(&2 + &1))

_.includes([1, 2, 3], 2)  // Enum.member?([1, 2, 3], 2)

_.filter([1, 2, 3], n => n < 3)  // Enum.filter([1, 2, 3], &(&1 < 3))

Other commonly used Lodash functions such as _.uniq (Enum.uniq), _.find (Enum.find), _.keyBy (Enum.group_by), etc. also have their counterparts in the Elixir standard library.

Getting Nested Values

I’ve also come to heavily rely on Lodash’s _.get and _.set functions to grab and update values in deeply nested data structures.

Using _.get lets me grab a nested value (or undefined) even if the intermediary objects and arrays don’t exist. For example, instead of writing:


if (foo && foo.bar && foo.bar.baz) {
  return foo.bar.baz.bot;
}

I can simply write:


return _.get(foo, "bar.baz.bot");

When I first started working with Elixir, I really missed being able to do this. Working with complex, nested data structures felt so clunky! That was before I found out about the awesome power of Elixir’s Access behavior and the family of functions built around it.

In Elixir, we can use the get_in function to grab values (or nil) out of nested structures, even if the intermediary values don’t exist:


get_in(foo, [:bar, :baz, :bot])

We can even pass in dynamic lookup fields, which would have required string manipulation in the Javascript example:


get_in(foo, [:bar, some_id, :baz])

Additionally, we can use Accessor functions to take our Elixir-foo to the next level. For example, we could grab the second user’s name (if it exists, otherwise we get nil):


get_in(..., [:users, Access.at(1), :name])

Or we could grab all of the users’ names:


get_in(..., [:users, Access.all(), :name])

If we wanted any of these values or intermediary values to have a default value, we could use Access.key:


get_in(..., [:users, Access.all(), Access.key(:name, "Anonymous")])

Let’s see Lodash’s _.get do that!

Setting Nested Values

All of these ideas apply to updating values as well. We can use put_in to directly set a value in a nested data structure, or update_in to update it with a function we provide.

For example, we can set values deep in a data structure, even if the intermediary values don’t exist, with put_in and Access.key:


put_in(%{}, [Access.key(:foo, %{}), :bar], "baz")

Similarly, we can update values with update_in or get_and_update_in.

If the Accessors provided by Elixir’s Access module aren’t enough for your use case, you can even write your own custom accessor functions!

Out of the Box Chaining

Elixir’s proverbial cherry on top is undoubtedly its built-in pipe operator.

To pipe Lodash function calls together, you need to explicitly construct a function chain with _.chain, passing in your initial value, and then call _.value at the end of your chain to retrieve the resulting value.

For example, let’s say we want to count the number of orders a set of users has made:


_.chain(users)
 .map("orders")
 .map(orders => orders.length)
 .sum()
 .value();

Because of Elixir’s stateless, functional nature, the barrier of entry for starting a chain is nonexistent:


users
|> Enum.map(&(&1.orders))
|> Enum.map(&length/1)
|> Enum.sum

Final Thoughts

I’ve yet to find a problem easily solvable with Lodash that isn’t easily solvable with an out-of-the-box tool provided by Elixir. In my experience, Elixir has proven to be incredibly more flexible and more powerful than Lodash.

While I originally felt uncomfortable and clumsy working with data in Elixir, my ever growing understanding of the tools the language provides is helping me regain my confidence.

If you haven’t already checked out Elixir, do it!

If you’re new to Elixir and feeling like a fish out of water, my only advice is to stick with it and read through the guides and documentation. You’ll be swimming again in no time.

Using Apollo Client with Elixir's Absinthe

Written by Pete Corey on Apr 10, 2017.

Last week I wrote about how I’m using Create React App in conjunction with the Phoenix framework to get off the ground incredibly quickly when building single page applications.

In that post I gave a teaser of how you can integrate your React front-end with your Elixir/Phoenix back-end using GraphQL and the Apollo client.

Let’s dive deeper into how we can wire up an Apollo driven React application to our Absinthe/Phoenix back-end.

Getting Started

Before we get started, let’s make sure we’re on the same page.

The Apollo client is a powerful GraphQL client with a variety of framework-specific integrations. Absinthe is an Elixir-powered GraphQL server implementation with built-in support for the Phoenix framework.

Apollo + Absinthe = 😍

In the past I’ve talked about the basics of getting started with Apollo client and Absinthe. Be sure to check out those instructions, and read through the Apollo documentation and the Absinthe guides if you’re unfamiliar with either tool.

For this article, I’ll assume you’re using a project setup similar to the one I described last week. That is, you’re running a React front-end application served through the Create React App tooling that connects to a Phoenix back-end application.

Once that’s all set up, we can spin up our React front-end by navigating to our React application’s folder and running:


npm start

Similarly, we can spin up our Phoenix back-end server by navigating to our Elixir project and running:


mix phoenix.server

Out of the box, our React application will run on port 3000, and our Phoenix server will run on port 4000.

Wiring Our Front-end to Our Back-end

As we mentioned last week, we need a way to tell our React application how to communicate with our back-end Phoenix applications. We do this by giving our application the URI to our GraphQL endpoint.

In different environments, this endpoint might change. That is, our staging environment might point to a different GraphQL endpoint than our production environment.

This means we can’t hardcode these endpoints into our front-end code.

So what do we do?

Thankfully, Create React App lets us pass custom environment variables into our front-end applications as long as they’re prefixed with REACT_APP_. These environment variables are passed into the application by the build tool and can be accessed through the process.env object.

Let’s assume that our GraphQL endpoint will be passed in through the REACT_APP_GRAPHQL_URI environment variable. We can use this to build Apollo’s network interface:


const networkInterface = createNetworkInterface({
    uri: _.get(process.env, "REACT_APP_GRAPHQL_URI"),
});

Now when we spin up our React application, we need to be sure to set REACT_APP_GRAPHQL_URI, otherwise our call to createNetworkInterface will fail:


REACT_APP_GRAPHQL_URI="http://localhost:4000/graphql" npm start

Now our React application knows where to find our Absinthe-powered GraphQL server.

Perfect!

Using a Custom Watcher… Partially

While our setup is now fully functional, having to manage two different development servers is cumbersome. Instead, let’s write a custom Phoenix watcher than spins up our Create React App development server whenever we start our Phoenix server.

We can do this by adding a new watcher to our Endpoint configuration in config/dev.exs:


config :hello_create_react_app, HelloCreateReactApp.Endpoint,
  ...
  watchers: [npm: ["start", cd: Path.expand("priv/hello_create_react_app/")]]

Now whenever we fire up our Phoenix server with mix phoenix.server or even iex -S mix phoenix.server, our Create React App development server (npm start) will spin up as well.

Remember, we still need to set REACT_APP_GRAPHQL_URI!


REACT_APP_GRAPHQL_URI="http://localhost:4000/graphql" mix phoenix.server

Fantastic!


Unfortunately, there’s currently a problem with this solution.

For some reason, when Create React App’s npm start command is executed through a watcher, which ultimately boils down to a call to System.call "npm", ["start"], ..., killing the Phoenix server will not kill the Create React App development server running in the background.

Killing your Phoenix server and trying to spin it up again will give you this error from the npm start command:


Something is already running on port 3000.

You’ll need to manually find the orphaned node process and kill it before once again restarting the Phoenix server.

I believe this problem is related to this issue on Github. Hopefully it will be fixed soon.

Integrating with our Release Manager

We know that we can point our React front-end to different back-ends with our REACT_APP_GRAPHQL_URI environment variable, but how do we automate this?

Is there a way to incorporate this into our release process?

If you’re using edeliver to generate your releases, you’re in luck. You edeliver configuration file can be customized to set REACT_APP_GRAPHQL_URI according to your build target.

Your edeliver configuration (.edeliver/config) is really just a bash script that’s executed before each edeliver task. This means that we can conditionally set REACT_APP_GRAPHQL_URI based on the environment we’re building for:


if [[ "$DEPLOY_ENVIRONMENT" = "production" ]]
then
  REACT_APP_GRAPHQL_API="http://production/graphql"
fi

if [[ "$DEPLOY_ENVIRONMENT" = "staging" ]]
then
  REACT_APP_GRAPHQL_API="http://staging/graphql"
fi

We can then add a compile hook to build our React application’s static bundle:


pre_erlang_clean_compile() {
  status "Installing NPM dependencies"
  __sync_remote "
    [ -f ~/.profile ] && source ~/.profile
    set -e

    cd '$BUILD_AT/priv/hello_create_react_app'
    npm install $SILENCE
  "

  status "Building React application"
  __sync_remote "
    [ -f ~/.profile ]
    set -e

    cd '$BUILD_AT/priv/hello_create_react_app'
    npm run build $SILENCE
  "
}

Now our React application should be built into priv/hello_create_react_app/build/, which is where our Phoenix application expects to find it.

Additionally, when it’s served by our Phoenix application it will connect to either our staging or production GraphQL endpoint depending on the environment the particular release was built for.

Now that our release manager is handling our front-end build process, all we need to worry about it building our application.

Final Thoughts

Once again, I’m very happy with this setup!

So far the combination of using React with Apollo and communicating with my Phoenix server using Absinthe has been a very powerful and productive combination.

As I mentioned last time, building your front-end application independently from your back-end application can offer up interesting optimizations if you choose to go that route.

Alternatively, you can configure your Create React App to be served as a static asset from your Phoenix application. Hopefully this article has shown that that’s a fairly painless process.

Using Create React App with Phoenix

Written by Pete Corey on Apr 3, 2017.

Contrary to what I said a couple weeks ago, I’ve decided to build the front-end of Inject Detect, as a React application.

Wanting to get off the ground quickly, I wanted to use Create React App to generate my React application boilerplate and tooling. While I wanted to use Create React App, I still wanted my React app to live within the context of a Phoenix application.

How could I combine these two worlds?

It took a little fiddling, but I’ve landed on a configuration that is working amazingly well for my needs. Read on to find out how I integrate all of the magic of Create React App with the power of a Phoenix application!

Front-end Demolition

To start, we won’t need Brunch to manage our project’s front-end static assets.

When creating a new Phoenix project, either leave out Brunch (mix phoenix.new ... --no-brunch), or remove brunch from your existing project by removing the Brunch watcher from your config/dev.exs configuration, and by removing brunch-config.js, package.json, and the contents of node_modules and web/static.

We also won’t need any of the initial HTML templates a new Phoenix project generates for us.

You can skip the generation of these initial files by giving mix phoenix.new a --no-html flag, or you can just ignore them for now.

Now that we’ve torn a massive hole in the front-end of our Phoenix application, let’s fill it back in with a React application!

Creating a React App

We’ll be using Create React App to generate our React application’s boilerplate and to wire up our front-end tooling.

We want Create React App to work largely without any interference or tweaking, so we’ll create our new front-end application within the /priv folder of our Phoenix project:


cd priv
create-react-app hello_create_react_app

What you choose to call your React project is entirely up to you. In this case, I chose to replicate the name of the overarching Phoenix project.

To give myself a little extra control over the base index.html file generated by Create React App, I chose to immediately eject my React application at this point:


cd hello_create_react_app
npm run eject

You now have a fully functional front-end application. You can spin up your development server by running npm start within the priv/hello_create_react_app folder.

Your React application should automatically start serving from port 3000!

Front-end Meets Back-end

Now we’re in a strange spot.

In development our React application will spin up and run on port 3000 but has no out-of-the-box way to interact with our back-end. Similarly, our Phoenix application runs on port 4000, but no longer serves any kind of front-end.

How do we join the two?

The answer is fairly simple. Our React application should be built in such a way that it can be told to communicate with any back-end service over whatever medium we choose.

We configure this communication by passing in the URL of our backend service through environment variables. The Create React App tooling will populate env.process for us with any environment variables prefixed with REACT_APP_.

With this in mind, let’s connect our React application to our back-end using Apollo client:


const networkInterface = createNetworkInterface({
    uri: _.get(process.env, "REACT_APP_GRAPHQL_URL") || "http://localhost:4000/graphql"
});

Locally, we can set REACT_APP_GRAPHQL_URL when we spin up our Create React App tooling:


REACT_APP_GRAPHQL_URL="http://localhost:1337/graphql" npm start

During staging and production builds, we can set this environment variable to either our staging or production back-ends, respectively.

Lastly, we’ll need to configure our Phoenix server to allow requests from both of our development servers. Add the CORSPlug to your endpoint just before you plug in your router:


plug CORSPlug, origin: ["http://localhost:3000", "http://localhost:4000"]

For more flexibility, pull these CORS endpoints from an environmental configuration.

Deployment Freedom

Because our front-end application exists completely independently from our Phoenix application, we can deploy it anywhere.

Running npm run build in our priv/hello_create_react_app folder will build our application into a static bundle in the priv/hello_create_react_app/build folder.

This static bundle can be deployed anywhere you choose to deploy static assets, such as S3 or even GitHub Pages!

Because your front-end content is served elsewhere, your back-end Phoenix application will only be accessed to resolve queries or perform mutations, rather than to fetch every static asset requested by every user.

Out of the box, this inherent separation between the front-end and the back-end offers nice scaling opportunities for your application.

Serving React from Phoenix

While serving your front-end separately from your back-end can be a powerful tool, it’s often more of a burden when you’re just getting out of the gate.

Instead, it would be nice to be able to serve your front-end React application from your Phoenix application.

Thankfully, this is a breeze with a few configuration changes.

First things first, we want our application’s root URL to serve our react application, not a Phoenix template. Remove the get "/" hook from router.ex.

Now we’ll want to reconfigure our Phoenix endpoint to serve static assets from our React application’s build folder, not priv/static:


plug Plug.Static,
  at: "/", 
  from: "priv/hello_create_react_app/build/",
  only: ~w(index.html favicon.ico static)

Unfortunately, navigating to our root URL doesn’t load our application. However, navigating to /index.html does!

We’re almost there.

We need to tell Phoenix to load and serve static index.html files when they’re available. The plug_static_index_html plugin makes this a one line change.

Just before we wire up Plug.Static in our endpoint, configure the application’s root URL to serve index.html:


plug Plug.Static.IndexHtml,
  at: "/"

That’s it! We’re serving our React application statically from within our Phoenix application!

Now any deployments of our Phoenix application will contain and serve the last built React application in its entirety. Be sure to set your REACT_APP_ environment variables during your Phoenix release build process!

Final Thoughts

I’ve been developing with this setup for the past few weeks, and I’m extremely satisfied with it so far.

Using Create React App gets me off the ground quickly with a functioning boilerplate and fantastic tooling. I don’t have to waste time restructuring my Phoenix application or tweaking build configurations.

The ability to quickly integrate my React application with an Elixir-powered Phoenix back-end means that I don’t have to sacrifice speed of development for power or scalability.