Introduction
React Over Crystal, Kemal, & Yarn
Current version is 0.1.0
Welcome to the ROCKY Stack
I built this as an experiment to put together the best libraries to build a modern yet simple stack.
I chose to base my stack
React - Solid front end framework backed by Facebook
Crystal - A powerful new language with syntax similar to ruby but is as fast as “C”
Kemal - Super light weight http framework made by Serdar Doğruyol
Yarn - The fastest package manager also made by Facebook
Installation
Follow the code on the right for the installation commands that you will have to run on your operating systems terminal / console.
Requirements
Rocky Project
git clone https://github.com/codingphasedotcom/rocky
Download or clone the ROCKY Project
https://github.com/codingphasedotcom/rocky
homebrew for mac
OS X (Mac)
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
Homebrew
brew update
brew install crystal-lang
brew install yarn
Make sure you have homebrew
Ubuntu / Linux
curl https://dist.crystal-lang.org/apt/setup.sh | sudo bash
sudo apt-get install crystal
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
Debian / Ubuntu
For other OSes and distros check the official documentation.
https://yarnpkg.com/en/docs/install#linux-tab
Dependencies
Get Crystal Dependencies
#terminal
shards install
Get all the “Backend” crystal dependencies
Get Yarn Dependencies
#terminal
yarn install
Get all the “Frontend” dependencies
Get Gulp
npm install --global gulp-cli
Install Gulp to be
Getting Started
#terminal
yarn run server
To test everything is good run the server.
Now if you visit http://localhost:3000/
you should see the welcome home page
Folders Structure
#Folders
|-- .bowerrc
|-- .jshintrc
|-- .jshintrc2
|-- Gruntfile.js
|-- README.md
|-- bower.json
|-- karma.conf.js
|-- package.json
|-- app
|-- app.js
|-- db.js
|-- directoryList.md
|-- index.html
|-- mddir.js
|-- routing.js
|-- server.js
|-- _api
|-- api.groups.js
|-- api.posts.js
|-- api.users.js
|-- api.widgets.js
|-- _components
|-- directives
|-- directives.module.js
|-- vendor
|-- directive.draganddrop.js
|-- helpers
|-- helpers.module.js
|-- proprietary
|-- factory.actionDispatcher.js
|-- services
|-- services.cardTemplates.js
|-- services.cards.js
|-- services.groups.js
|-- services.posts.js
|-- services.users.js
|-- services.widgets.js
|-- _mocks
|-- mocks.groups.js
|-- mocks.posts.js
|-- mocks.users.js
|-- mocks.widgets.js
This is an example not final
HTTP
Routing
Simpler Route
#src/routes/web.cr
get "/" do
"Hello World!"
end
All Routes are declared on the file src/routes/web.cr
when you visit http://localhost/
you will see the page return “Hello World!”
This endpoint retrieves all kittens.
REST Calls
#src/routes/web.cr
get "/" do
.. show something ..
end
post "/" do
.. create something ..
end
put "/" do
.. replace something ..
end
patch "/" do
.. modify something ..
end
delete "/" do
.. annihilate something ..
end
You can handle HTTP methods as easy as writing method names and the route with a code block. Kemal will handle all the hard work.
Static Files
#Files
app/
src/
your_app.cr
public/
js/
jquery.js
your_app.js
css/
your_app.css
index.html
Open index.html and add
#src/public/test.html
<html>
<head>
<script src="/js/jquery.js"></script>
<script src="/js/your_app.js"></script>
<link rel="stylesheet" href="/css/your_app.css"/>
</head>
<body>
...
</body>
</html>
Add your files to public directory and Kemal will serve these files immediately.
Static File Options
#src/rocky.cr
serve_static false
Disabling Static Files
By default Kemal serves static files from public folder. If you don’t need static file serving at all(if you are only running an API) you can disable it
Error Handling
Error handlers run within the same context as routes and before filters which means you get all the power of those.
404 Not Found
error 404 do
"This is a customized 404 page."
end
When a Kemal::Exceptions::NotFound
exception is raised, or the response’s status code is 404, the error 404 handler is invoked:
You can customize the built-in error 404 handler.
Custom error handlers for status codes
Just like error 404 handler you can install custom error handlers for different status codes.
error 403 do “Access Forbidden!” end
get “/” do |env| env.response.status_code = 403 end
Views
Render a View
Views are server side rendered pages
#src/routes/web.cr
get "/account" do
render "src/views/hello.ecr"
end
Macro | Value1 | Detail |
---|---|---|
render | src/views/hello.ecr | you pass down the ecr view that you want to render on that route |
Pass Variables to View
On The Route
#src/routes/web.cr
get "/user" do |env|
name = "Joe"
render "src/views/hello.ecr"
end
You declare the route route and inside the block you declare the variable.
On The View
#src/views/hello.ecr
<div>
<%= name %>
<div>
Now inside the ecr file which is the view you want to render. You want to do an embedded tag with the name of the variable so it can show on your page.
Layouts
Layouts are a great way to keep your code DRY (Dont Repeat Yourself) For example lets say all your pages have the same header and footer throughout all the pages and all that changes is the content area do you go and copy the header and footer to every page No… we just make one main layout and then set content tag where you will show your view.
On The Route
On The Route
#src/views/pages/user.ecr
get "/user" do
name = "joe"
render "src/views/pages/user.ecr", "src/views/layouts/main.ecr"
end
Macro | Value1 | value2 | Detail |
---|---|---|---|
render | src/views/hello.ecr | src/views/layouts/main.ecr | you pass down the ecr view that you want to render on that route and layout page |
view location | layout location |
On The View
On The View
#src/views/hello.ecr
<div class="content-area">
Hey, here goes my html
</div>
Just put the code you want to show up for that view
On The Layout
On The Layout
#src/views/layouts/main.ecr
<html>
<head>
<title>My Kemal Application</title>
</head>
<body>
<header>
<ul class="menu">
<li><a href="#">Home</a></li>
<li><a href="#">Contact</a></li>
</ul>
</header>
<%= content %>
</body>
</html>
Use <%= content %>
tag to display the page content on the layout
content_for & yield_content
content_for is a great for situations where you might want to change something from the layout on every view. For example a page title or a css script.
On The View
On The View
#src/views/pages/hello.ecr
<% content_for "title" do %>
<title>My Kemal Application</title>
<% end %>
<% content_for "css" do %>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<% end %>
<div class="content-area">
this will be the view content
</div>
<% content_for "javascript" do %>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<% end %>
Use the content_for
and give it a name. You can have multiple content_for macros on a view. For example one for the title, another for css, and another for javascript.
On The Layout
On The Layout
#src/views/layouts/main.ecr
<html>
<head>
<%= yield_content "title" %>
<%= yield_content "css" %>
</head>
<body>
<header>
<ul class="menu">
<li><a href="#">Home</a></li>
<li><a href="#">Contact</a></li>
</ul>
</header>
<%= content %>
<%= yield_content "javascript" %>
</body>
</html>
add the yield_content
with the name of the content you want to display.
First View
#src/views/includes/navigation.ecr
<ul class="menu">
<li><a href="#">Home</a></li>
<li><a href="#">Contact</a></li>
</ul>
You can include any view in another view
#src/views/layouts/main.ecr
<html>
<head>
<%= yield_content "title" %>
<%= yield_content "css" %>
</head>
<body>
<header>
<ul class="menu">
<li><a href="#">Home</a></li>
<li><a href="#">Contact</a></li>
</ul>
</header>
<%= render "src/views/includes/navigation.ecr" %>
<%= content %>
<%= yield_content "javascript" %>
</body>
</html>
Database
Views
React Over Crystal and Kemal
Welcome to the ROCKY Stack
require 'kittn'
api = Kittn::APIClient.authorize!('meowmeowmeow')
api.kittens.get
import kittn
api = kittn.authorize('meowmeowmeow')
api.kittens.get()
curl "http://example.com/api/kittens"
-H "Authorization: meowmeowmeow"
const kittn = require('kittn');
let api = kittn.authorize('meowmeowmeow');
let kittens = api.kittens.get();
The above command returns JSON structured like this:
[
{
"id": 1,
"name": "Fluffums",
"breed": "calico",
"fluffiness": 6,
"cuteness": 7
},
{
"id": 2,
"name": "Max",
"breed": "unknown",
"fluffiness": 5,
"cuteness": 10
}
]
This endpoint retrieves all kittens.
ORM
This endpoint retrieves all kittens.
Security
Views
React Over Crystal and Kemal
Welcome to the ROCKY Stack
require 'kittn'
api = Kittn::APIClient.authorize!('meowmeowmeow')
api.kittens.get
import kittn
api = kittn.authorize('meowmeowmeow')
api.kittens.get()
curl "http://example.com/api/kittens"
-H "Authorization: meowmeowmeow"
const kittn = require('kittn');
let api = kittn.authorize('meowmeowmeow');
let kittens = api.kittens.get();
The above command returns JSON structured like this:
[
{
"id": 1,
"name": "Fluffums",
"breed": "calico",
"fluffiness": 6,
"cuteness": 7
},
{
"id": 2,
"name": "Max",
"breed": "unknown",
"fluffiness": 5,
"cuteness": 10
}
]
This endpoint retrieves all kittens.