loading...

A Crystal app adventure!

franciscello profile image Franciscello ・4 min read

Introduction

We are starting an adventure: we are going to build a great-outstanding-marvelous application using the Crystal language!

But, since these are our first steps using the Crystal language, maybe we could start with a first simple app? 🤔 Yeah! It sounds good! So, this is the goal for this post: 3 steps for creating a simple app using Crystal! 🚀

1, 2, 3 … Hold it! We are assuming that you already have installed the Crystal language. But, what if you didn't? 😱

Well, in that case here it is step 0

  • Go to the Crystal language site and click on Install. There you'll find all you need to install the language compiler for your platform ... don't worry, we'll wait for you ...

and another step 0 😝:

  • In the overview section, you will find some great examples if you didn't use Crystal before.

a few minutes later

Are you ready? Great! Let's start!

Step 1: init is the magic word

So, first things first: assuming that our app is called my_app (if you can think of a better name, go ahead and rename it! 🙃) then we create the application using the same Crystal's command line, like this:

$ crystal init app my_app

And Crystal will reply:

create  my_app/.gitignore
   create  my_app/.editorconfig
   create  my_app/LICENSE
   create  my_app/README.md
   create  my_app/.travis.yml
   create  my_app/shard.yml
   create  my_app/src/my_app.cr
   create  my_app/spec/spec_helper.cr
   create  my_app/spec/my_app_spec.cr
Initialized empty Git repository in /great_projects/my_app/.git/

Perfect! We have the project with the Git repository already initialized and with a basic .gitignore (thanks Crystal! ❤️)

In the folder my_app/src/my_app.cr we have the entry point to our application. Although we may use other file, it is a standing point to start building our app.

Step 2: Hello world database!

Not the Hello World example! With step 1 we have a new Crystal App ready to grow! So let's continue with a more interesting example ... maybe we could connect to a database? Yeah! Let's do that!

We'll be using a MySQL database, It won't be necessary to install the database in our computer, instead we could use a Docker container! Here's the docker-compose.yml file:

version: '3'

services:
  db:
    image: mysql:8.0.17
    command: --default-authentication-plugin=mysql_native_password
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: root
    container_name: crystal_db
    ports:
      - 3306:3306

volumes:
  db:

Great! With this, we may start the container and have a MySQL database ready for us to use!

Let's start the container:

$ docker-compose up

If it's all good, then the response from docker should end with something like this:

crystal_db | Socket: '/var/run/mysqld/mysqlx.sock' bind-address: '::' port: 33060

Now, using our favourite database tool (in my case I'm using TablePlus), we may connect to the database using this configuration:

host: 127.0.0.1
port: 3306

user: root
password: root

And last (but not least) we will create a new database for our project called crystal123_db

CREATE DATABASE `crystal123_db`;
USE `crystal123_db`;

Step 3: (Actually) using the database from our app!

And here we are, the final step! We will need the corresponding MySQL-connector in order to use the database from our Crystal app.

First, we need to add the mysql-shard in our application's shard.yml file, like this:

dependencies:
  mysql:
    github: crystal-lang/crystal-mysql

And then, we install all the dependencies with:

$ shards install

Shards will reply:

Fetching https://github.com/crystal-lang/crystal-mysql.git
Fetching https://github.com/crystal-lang/crystal-db.git
Installing mysql (0.10.0)
Installing db (0.8.0)

Note: Shards is the Dependency manager for the Crystal language.

Now, let's try to connect to the database! (remember we called the database: crystal123_db ... a great name if you ask me 😎) And, since we are there, we will create a new table called bank_accounts (with to columns: name and amount)

# my_app.cr
require "mysql"

db = DB.open "mysql://root:root@localhost/crystal123_db"

db.exec "drop table if exists bank_accounts"
db.exec "create table bank_accounts (name varchar(30), amount int)"

Let's run the code using Crystal's command line:

$ crystal ./src/my_app.cr

Go to the database ... yes! The table bank_accounts was created!!

And for the same price, let's add 2 rows to the table. Here is the final version of my_app.cr:

# my_app.cr

require "mysql"

db = DB.open "mysql://root:root@localhost/crystal123_db"

db.exec "drop table if exists bank_accounts"
db.exec "create table bank_accounts (name varchar(30), amount int)"

# first row
db.exec "insert into bank_accounts values (?, ?)", "John", 100

# second row
db.exec "insert into bank_accounts values (?, ?)", "Sarah", 250

We run the application:

$ crystal ./src/my_app.cr

Let's check the database and ... yes! Now we have the table bank_accounts created and with 2 rows! We did it! 🎉

Farewell and see you later

We have reached the end of this first journey. To recap:

  • we have initialized a Crystal application using the command line.
  • we have installed a database (actually a container with the database)
  • and finally we have use the database from our Crystal application!

Hope you enjoyed it! Until the next Crystal adventure!😃

References:

Discussion

pic
Editor guide
Collapse
moopet profile image
Ben Sinclair

We have the project with the Git repository already initialized and with a basic .gitignore

Why would a language assume you were using one particular type of VCS? There's opinionated, and there's presumptive. I've never tried Crystal, but that bit puts me off it.

Collapse
franciscello profile image
Franciscello Author

Hi Ben! Thanks for reading and comment! I understand your point of view, but I think that the language gives us an initialized repository just to make our life easier. Git is a free and open source VCS and one of the most used, so I don't think the language is doing any harm. In case we don't want to use it, we can remove (rm) the repository folder and that's it!
Perhaps in the future there are more options (?) 🤷‍♂️
Anyway, I hope that that bit didn't put you off it and you keep trying the language! 😃

Collapse
straightshoota profile image
Johannes Müller

Git is the backbone for Crystal's dependency manager shards. If you want to make your project available in the Crystal ecosystem, there's no way around git.

So it's not just an opinionated choice but a functional requirement. Of course, when shards supports other distribution systems as well, this might need a revisit.

Collapse
citizen428 profile image
Michael Kohl

Many starter kits for frameworks etc. do that nowadays. I guess the intent is to make it most convenient for the majority and slightly inconvenient for others (a single rm).

Collapse
moopet profile image
Ben Sinclair

It seems like a really bad idea to me - it makes me wonder what other stuff they use magic for.

Thread Thread
citizen428 profile image
Michael Kohl

It wasn’t meant as an endorsement of the practice, more of a statement re the status quo. I fall more into your camp, I prefer more manual setups too.

Collapse
exts profile image
Lamonte

Crystal is open source, feel free to fork and add support for other VCS's - git's popular right now and so they went with that as the default. You're not forced to use the commands and you can easily delete the .git folder if you do.

Collapse
moopet profile image
Ben Sinclair

I'm aware you can remove it - I just think it's a bad practice to include things that aren't part of the purpose of the product. Facebook is popular, but I don't feel like including a facebook oauth library in my calculator app.