Why you should try Amber Framework
As web developers, we all have flirted with the idea of having the perfect web framework — one that is fun to work with, does not get in your way, catches bugs early, is easy to scale, easy to learn, deployable anywhere and adaptable to different architecture patterns without sacrificing performance.
Amber takes an aim to address these qualms by leveraging on Crystal Language and converging a series of widely accepted features.
Amber is a web application framework written in Crystal, which makes building web applications fast, simple, and enjoyable with blazing fast performance.
Here are a few good reasons to give it a try:
1. Crystal Language
Crystal as a programming language offers a high-level syntax with the performance and characteristics of a low-level language.
- Syntax — Write a program with highly expressive, yet more simplistic code that is easy to read without scarifying performance.
- Type System — Statically type-checked, so any type errors will be caught early by the compiler rather than fail on run-time. Fewer bugs.
- Null Reference Checks — All types are non-nilable in Crystal, and nilable variables are represented as a union between the type and nil. Again, fewer bugs.
- Macros— Crystal’s answer to meta-programming is a powerful macro system, which ranges from basic template to Abstract Syntax Tree inspection.
- Concurrency Model — Crystal uses green threads, called fibers, to achieve concurrency. Fibers communicate with each other using channels, as in Go or Clojure, without having to turn to shared memory or locks.
2. Extremely low learning curve
Amber is very easy to learn and pick up, with a friendly and easy to read Ruby-like syntax. Amber shares the same concepts as other popular web application frameworks that you find in other languages like Ruby, Express, Elixir and Laravel, making it easy to understand and familiar to work with.
3. Blazing fast performance
Amber is for programmers who want more performance, who enjoy working in a high-level scripting environment, with combine native execution speed and concurrency, without sacrificing joy in programming because of code complexity.
02:28:43 Request | Started 2018-01-07 14:28:43 - 05:00
02:28:43 Request | Status: 200 Method: GET Pipeline: web Format: html
02:28:43 Request | Requested Url: /
02:28:43 Request | Time Elapsed: 94.0µs
4. Convergence of features
Amber developers did not stop with Crystal features. Amber converges a wide range of accepted features from a broad series of web frameworks, especially with Ruby On Rails.
Controllers
Amber does not re-invent the wheel. It keeps you in familiar territory by embracing Model-View-Controller patterns and Convention over Configuration principles.
class UsersController < ApplicationController
# Filters are methods that are run "before", "after" a controller action.
before_action do
# runs for specified actions
only [:index, :world, :show] { increment(1) }
# runs for all actions
all { increment(1) }
end
after_action do
# runs for specified actions
only [:index, :world] { increment(1) }
end
def index
@users = Users.all
render("index.slang")
end
end
Views Templates
Amber supports a wide range of template languages. There are 4 different template languages currently supported: Slang, ECR, Mustache, and Temel.
Since Crystal is a compiled language, all view templates are pre-compiled. At run-time, all templates are loaded into memory. There are no disk reads, complex file caching, or template engine computation involved, allowing your pages to render swiftly.
doctype html
html
head
meta name="viewport" content="width=device-width,initial-scale=1.0"
title This is a title
css:
h1 {color: red;}
p {color: green;}
style h2 {color: blue;}
body
ul
- @users.each do |user|
li = "#{user.name} - #{user.email}"
Pipelines
A pipeline is a series of transformations throughout the request life-cycle. Each request interacts with a “pipe” at every step of the request. This differs from other HTTP middleware layers, where the request and response are separated in the stack.
Amber::Server.configure do |app|
pipeline :web, :auth do
plug Amber::Pipe::Logger.new
plug Amber::Pipe::Flash.new
plug Amber::Pipe::Session.new
plug Amber::Pipe::CSRF.new
end
pipeline :auth do
plug Authenticate.new
end
end
Parameters Validation
One of the most important aspects of validation is to prevent the widespread issue of invalid persisted data in programs.
Parameters Validation is your first line of defense. We can set a series of data correctness rules for a given controller-action. This allows for the separation of controller-action validation from model validation, by invalidating the request at an early stage preventing the execution of more demanding operations.
update_params = params.validation do
required(:name, "Your First Name is missing!") { |p| p.name? & !p.name.empty? }
required(:email, "Your email address is invalid!") { |p| p.email? & p.size.between? 1..10 }
required(:last_name) { |p| p.last_name? }
end
Routing
Amber defines routes explicitly in one central file. With the routes.cr file, it is easy to understand at a high level which transformations are being performed for each controller-action.
Routes can be scoped to a particular path. This is quite useful for representing: API versions, CMS, Admin areas, etc.
Web-sockets routes represents a full duplex communication channel over a TCP connection with low overhead, facilitating real-time data transfer form and to the Amber server.
routes :web, "/pages" do
get "/about", StaticController, :about
resources "/posts", PostController
websocket "/chat", ChatSocket
end
Channels
All web-socket messages are routed through channels. A channel represents a topic. Clients subscribe to a Topic send and receive new messages. Channels define 3 public methods:
- **handle_joined** - Called when a user joins a channel.
- **handle_message** - Called when a user sends a message to a channel. A common message handler will simply rebroadcast the message to the other subscribers with rebroadcast! method.
- **handle_leave** - Called when a user leaves the channel.
class HomeController < ApplicationController
def index
ChatSocket.broadcast("message", "chat_room:123", "message_new", {"message" => "A new visitor!"})
render("index.slang")
end
end
Object-Relational Mapping Agnostic
Amber model layer is not tied to any specific object-relational mapping library Instead it provides a default active record pattern ORM called Granite::ORM, for quick prototyping.
The developer is free to configure and use any of the Crystal available Object-Relational Mapping library available: Granite, Crecto, Jennifer, Lucky::Record, Active Record. This allows you to select the right tool for your project, without Amber get in your way.
require "granite_orm/adapter/sqlite"
class Comment < Granite::ORM::Base
adapter sqlite
has_many :posts
table_name comments
field name : String
field body : String
validate("Invalid Comment.", ->(comment : self) {
(comment.name != nil && comment.name != "") || (comment.body != nil && comment.body != "")
})
end
# Querying
# ORDER BY Example
posts = Post.all("ORDER BY created_at DESC")
# JOIN Example
posts = Post.all("JOIN comments c ON c.post_id = post.id
WHERE c.name = ?
ORDER BY post.created_at DESC",
["Joe"])
Amber CLI
Amber has a built in CLI tool, to make your life easier while developing applications.
Here is a list of the available commands:
d, deploy — Provisions server and deploys project.
db, database — Performs database maintenance tasks
e, encrypt — Encrypts environment YAML file. [env | -e — editor | — noedit]
x, exec — Executes Crystal code within the application scope
g, generate — Generate Amber classes (Controller, Migrations, Views, Models, Mailer, etc)
n, new — Generates a new Amber project
routes — Prints all defined application routes
w, watch — Starts amber development server and rebuilds on file changes
System Tests
Amber was built with testing in mind. Amber made it as simple as possible to and provides a built in System Test framework that runs consistently and fast.
class SomeFeature < GarnetSpec::System::Test
scenario "user visits amber framework and sees getting started button" do
visit "http://www.amberframework.org"
timeout 1000
click_on(:css, "header a.btn.btn-primary")
wait 2000
element(:tag_name, "body").text.should contain "Introduction"
end
end
5. Fast Prototyping and Scalability
Web application performance and Scalability are of huge importance when developing a business around internet services especially when we talk about driving more traffic, engagement, and increase brand loyalty. What’s more is slow downs and/or downtime can cost companies thousands of dollar.
Amber has some benefits to overcome these issues:
- Global type inference. You can program without type annotations except for a few cases where you are required to do so (generic type arguments). Amber still recommends to use types
- Amber allow for very quick prototyping, similar to dynamic languages. You can scaffold a project in 7 steps without touching one line of code.
- Amber gives you a high throughput with with no premature optimizations, and sub second response times. Thanks to Crystal, Amber has a low consumption of CPU, Memory, and disk space.
- Distributed binary — All amber projects compile to a binary that can be easily distributed. This makes deployments fast and easy.
- Catch bugs early. Programs are verified by before they can be executed. This rules out many programming errors Null reference checks to name one.
Where to start?
What you’ve seen here just barely scratches the surface of what Amber Framework can do. There’s so much more to help you build, organize, and scale your web applications. To start coding yourself, I’ll recommend following resources.
- From Zero to Deploy
- Amber Framework Guides
- Crystal Play — an online playground to run Crystal code.
- Amber Community Channel
- GitHub - help the community and star the project.
Lastly I must thank the Crystal and Amber Community for your support and contributions.