Introducing the Ecto library for Elixir
by Alexandre Dedourges, DevSec
What is Ecto? And what is it for?
When you develop an application in Elixir or any other type of programming language, you often need to interact with a database. Indeed, whether your application is a SaaS (Software as a Service), a game, a music application... you will often need to store data or use it. Whether it is identity data, scores or titles. To store them, you could use a MySQL or Postgres database for example. But how do you use this data in your application? That's where Ecto comes in. Ecto is what we could call a library on some languages like Python for example. It provides many tools that will allow you to interact with the databases.
Ecto is therefore a database wrapper and a query generator specific to Elixir. But its use is not limited to that. That's why we're going to see in more detail the possibilities that Ecto offers us.
An exclusive Elixir toolbox
Elixir is a functional programming language that runs on the Erlang Virtual Machine (BEAM). It is a powerful language, especially for building applications that will be used on a large scale. Indeed, it makes maintenance and scalability more accessible and simpler. Its large-scale use means that it is often used alongside a database. As a consequence, it was necessary to create a tool allowing to interact with them: Ecto.
Ecto offers developers the possibility of creating databases, storing data in them, managing them, validating them, converting them to the right format (SQL/Postgres Data -> Elixir Struct and Elixir Struct -> SQL/Postgres Data)...
Ecto, a single tool with several features
Ecto allows you to do several different things. To do so, it is divided into four components. The changesets, the queries, the repos and the schemas.
Changesets
Changesets are very useful, as they allow you to check and validate data before it is applied to the database. This avoids any problems that could cause damage to your application.
Queries
The Queries will allow us to query our database via the Repos. Thanks to Ecto, these queries will not need to be written in MySQL or Postgres. The queries can indeed be written with the Elixir syntax. This is very practical because it avoids having to know other syntaxes. Here we have only one syntax for several types of databases. Moreover, Elixir queries are secure and can be decomposed.
Repos
The repositories will allow the "connection" between a SQL database and the Elixir application. The communication is based on an "Adapter" and the connection information to the database. This is what will link the code in Elixir to the SQL databases. It then becomes possible to query the database using Elixir syntax.
Schemas
Finally, Schemas are used to match the data in your database with data structures in Elixir. Without it, it would not be possible to process the data in the database directly in Elixir. Moreover, Schemas have other uses.
Repos, database wrapper
They allow you to connect to the database and define its parameters in order to perform actions between the application and the database.
To define a Repository you can proceed as follows:
Then we define the Repo configuration in our application environment:
Schemas, data converters
Schemas allow you to define in which form the data will be processed. Here is an example of a Schema in Elixir :
In this example, we want to define a User. Thanks to our Schema, we can already define that we will work on the "users" table of our database. Each user will also have the possibility to be defined by a name, a first name and an age.
So here we have defined, thanks to our Schema, what our "users" table would contain, users defined by their name, first name and age. Thanks to this, we have access to a brand new type of structure. This one is automatically generated by Ecto in our application: the User structure. This new structure is defined as follows:
For example for a user named Cry Ptr being 25 years old we would have :
We could then interact with our database in the following way:
However, this is not the best way to do it. Indeed, as long as we have not created the Changesets, no verification will be done on the data we want to apply to the database.
Changesets, data validators
Changesets are very interesting tools, because they allow you to validate data via filters, validations and casts before they are applied in the table. Changesets are defined in the same place as Schemas. For example :
The changeset function starts by passing the structure to the cast function and a list of authorized fields. This is where the validation of the authorized fields will be done. The expected output is a changeset.
If some fields provided as parameters are not listed as accepted parameters, then these fields will not be taken into account. For example, a "phone_number" parameter would not be taken into account when creating the changeset.
After the cast we can pass our changeset in different validation functions to check the values of our fields. In the example above, we ask for the presence of a value for the name and the email address. We check that the email is well formatted and that the age is between 18 and 100. If it is greater than 100 or less than 18, if the email is not valid or if the name and email are not filled in, then the data and therefore the changeset will be invalid. If this happens, the changes will not be applied to the database and an error will be transmitted.
Example:
Note that it is possible to create several changesets for a single table. For example a changeset for the creation of a user and another one for the modification...
Requests to query the database
Finally, it is possible to query the database with Ecto, but more precisely to query it via queries written in Elixir. This allows to use only one type of language. Thanks to this, there is no need to juggle between different syntaxes. There is only one syntax and one language.
Here is an example of a query that can be created in Elixir via the Ecto Queries. This query will retrieve all users who are older than 18 or who do not have an email address. This request will first go through our Repo so that it is "translated" into the right language. Then it will be used to query the database and return all the results obtained.
Thanks to Ecto it is also possible to query a table directly. But it will be necessary to specify in the query the data to be retrieved.
Finally, the use of Ecto prevents attacks like SQL Injections. This type of attack was ranked #1 and #3 in 2017 and 2021 by OWASP (Open Web Application Security Project) in its « Top 10 Web Application Security Risks ».
Ecto without database.
A particularity of Ecto is the fact that it can be used without a database. Indeed, Schemas and Changesets can be used in different ways. For example, if you want to process data with a specific format without necessarily persisting them in a database. With the help of the various validation functions provided by Ecto, you can validate and filter your data efficiently.
Ecto, step by step
The basics
To start using Ecto in a Project, you can start by using the Mix command to create an application.
Then go to the newly created folder "project". In this folder you should find a file "mix.exs". You will have to modify this file so that you can use Ecto and communicate with a Postgres database from your application. To do this, you need to add the following dependencies to the project:
Once done, you must now apply these dependencies to the project via the command :
Creation of the Repo
To create a Repo we have a command that creates it automatically.
This command will automatically generate a basic configuration for the database connection in the « config/config.exs » file, and an « Adapter ».
You will have to modify this configuration according to the parameters of your database. And add the following line in the file:
This line will be useful later to be able to execute Ecto commands from the command line.
The Adapter will be declared in the Project.Repo module defined by the « lib/project/repo.ex » file
We must now indicate to our application that Ecto must be launched when it starts. To do this we will modify the supervision tree of our application.
This one is located in the « lib/friends/application.ex » file.
We can now create our database with the following command:
Creation and modification of tables
To create and modify tables, we have another tool that is very useful in Ecto: Migrations. Every time we have to modify one table or more, we have to create a migration file and execute it.
To do this you can run the command :
This should have generated a new file similar to this:
priv/repo/migrations/20220606160123_create_users.exs
Its content looks like this:
Now let's imagine that we want to create a "User" table. To do this, we need to modify this migration file to express the changes we want to make. We could then have the following file:
We can now execute the migrations with the command :
Creation of Schemas
It is now possible to create the Schema file «** lib/project/user.ex** ». This one will allow us to map the data of our database to an Elixir structure.
Our Schema will therefore look like this:
Creation of the Changesets
Now that our Schema is created, we can assign validations, filters...
To do this we'll need Changesets. It is very common to define Changesets with Schemas to make sure that the data we want to use is correct. It is possible to create changeset functions directly so that they can be reused when needed. The most basic changeset function is the following:
This function takes as input a structure (in our case it would be a user) and parameters. Then it returns a changeset.
From these changesets, it is possible to perform many verification actions... For example, we want the email and name of a user to be always present. We can then imagine the following changeset:
From now on, when we try to create a user with an empty name or an empty email, the changeset obtained in output will be invalid. Therefore it will be impossible to insert this user into the database.
Many other possibilities are possible from Ecto, but the steps above represent the most basic actions of Ecto. If you want to know more, feel free to consult the online documentation.
Ecto, a powerful tool for databases, but not only
Ecto is therefore a very powerful and interesting tool that will allow all applications to use databases. It is an indispensable tool for all developers using Elixir to work with databases. At Cryptr, we use Ecto to guarantee speed, fluidity, scalability, but also security.The identity data, related to SSO connections, for example, will then be more secure.
So, are you ready to learn more? We tell you more at Cryptr.
Add enterprise SSO for free
Cryptr simplifies user management for your business: quick setup, guaranteed security, and multiple free features. With robust authentication and easy, fast configuration, we meet businesses' security needs hassle-free.