shivneri-framework
Published in

shivneri-framework

Rest Api in crystal lang using Shivneri

Introduction

  • Concurrency using green threads known as fiber (similar to go routine)
  • Object oriented with focus on using struct for better memory management
  • Performance like c language
  • Package dependency manager using Shards
  • Statically type
  • Ruby syntax
  • Provides components - Wall, Shield and Guard. Components help modularize the application
  • Provides you ways to write clean & maintainable codes
  • Dependency Injection
  • Everything is configurable — you can configure your session store, view engine, websocket etc

Let’s Code

Project Setup

dependencies:
shivneri:
github: ujjwalguptaofficial/shivneri
require "shivneri"include Rest# TODO: Write documentation for `Rest`
module Rest
VERSION = "0.1.0"
Shivneri.open do
puts "app is started"
end
end
module Rest
module Controller
class DefaultController < Shivneri::Controller @[DefaultWorker]
def index
text_result("Welcome to Shivneri")
end
end end
end
  • Shivneri::Controller
  • DefaultWorker
  • text_result
  • json_result - used to return result of type json
  • html_result - used to return result of type html
  • file_result - used to return a file.
require "./controllers/default_controller"module Rest  include Controller  def self.routes
return [
{
controller: DefaultController,
path: "/*",
}
]
end
end
require "shivneri"
require "./routes"
include Rest# TODO: Write documentation for `Rest`
module Rest
VERSION = "0.1.0"
Shivneri.routes = routes Shivneri.open do
puts "app is started"
end
end

REST

module Rest
module Controller

class UserController < Shivneri::Controller

end

end
end
require "./controllers/default_controller"
require "./controllers/user_controller"
module Rest include Controller def self.routes
return [
{
controller: DefaultController,
path: "/*",
},
{
controller: UserController,
path: "/user",
},
]
end
end

Add User

module Rest
module Controller

class UserController < Shivneri::Controller

@@users = [] of NamedTuple(id: Int32, name: String, gender: String)
@@last_user_id = 0;
@[Worker("POST")]
@[Route("/")]
def add_user
new_user = {
name: body["name"].as_s,
gender: body["gender"].as_s,
id: @@last_user_id += 1
}
@@users.push(new_user) return json_result(new_user, 201) end
end

end
end
  • We have created two static variable- users and last_user_id . users maintain list of user & last_user_id is used for tracking last id of user.
  • We have created a method add_user which is a worker method. We have marked it as worker using annotation “Worker”.
  • We are restricting this worker to only post request by passing only “POST” method in Worker annotation. It means that when http method will be post then only this worker will be called.
  • We have changed router of “add_user” to “/” method by using annotation “Route”. If we won’t change route then by default route is method name of worker.
  • We are extracting data from body and storing it in a variable new_user.
  • We are adding new_user variable in our users stores.
  • In the end we are returning added user as json result using method “json_result” with http status code 201 (resource created).

Get User

@[Worker("GET")]
@[Route("/{user_id}")]
def get_user
user_id = param["user_id"].to_i
user = @@users.find{|u| u[:id] == user_id}
if (user != nil)
return json_result(user)
else
return text_result("invalid user", 404)
end
end
  • We have added a method “get_user” as worker.
  • We are restricting this worker to only GET request by passing only “GET” method in Worker annotation.
  • We have changed router of worker to “/{user_id}” using annotation Route. The route contains a variable “user_id” which will hold the user_id value from route.
  • In method - we are extracting user id from route param and checking if any user exist for that id. If user is found then we return user as json result otherwise return text result “invalid user” with status code 404.

Update User

@[Worker("PUT")]
@[Route("/")]
def update_user
user = body.to_tuple(NamedTuple(id: Int32, name: String, gender: String));
index_of_saved_user = @@users.index { |q| q[:id] == user[:id] }
if (index_of_saved_user == nil)
return text_result("invalid user", 404)
else
@@users[index_of_saved_user.as(Int32)] = user
return text_result("user updated")
end
end
  • We have created a method “update_user” and marked it as worker.
  • We are restricting this worker to only PUT request by passing only “PUT” method in Worker annotation.
  • We have changed router of worker to “/” using annotation Route.
  • In method - we are extracting user from body.
  • We are checking if a user exist and if exist then update the user and return text result “user updated” .
  • If user does not exist then we return text result “invalid user” with status code 404 .
@[Worker("DELETE")]
@[Route("/{user_id}")]
def remove_user
user_id = param["user_id"].to_i
index_of_saved_user = @@users.index{|u| u[:id] == user_id}
if (index_of_saved_user != nil)
@@users.delete_at(index_of_saved_user.as(Int32))
return text_result("user deleted")
else
return text_result("invalid user", 404)
end

end
  • We have added a method “remove_user” as worker.
  • We are restricting this worker to only DELETE request by passing only “DELETE” method in Worker annotation.
  • We have changed router of worker to “/{user_id}” using annotation Route. The route contains a variable “user_id” which will hold the user_id value from route.
  • In method - we are extracting user id from route param and checking if any user exist for that id. If user is found then we delete that user & return message “user deleted” as text result otherwise return text result “invalid user” with status code 404.

--

--

Component based MVC framework for crystal targeting good code & modularity.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Ujjwal Gupta

Frontend lead Polygon | Creator of jsstore, mahaljs | sqlweb, fortjs | opensource creator | we3, blockchain, solidity | javascript