Прийшов час поговорити про REST архітектуру додатку та її реалізацію на Sinatra.
Особисто мені коштувало багато зусиль зрозуміти, що таке REST. Тому прошу не чіплятися до того, наскільки я спрощую термінологію, щоб сфокусуватися на самій темі.
REST - це Representational State Transfer, так звана "передача стану представлення". Фактично - це спосіб організації доступу до ресурсів. Відповідно до цієї архітектури використовується чотири типи HTTP запитів - GET, POST, PUT і DELETE.
- GET - отримати ресурс тільки для читання
- POST - створити новий ресурс
- PUT - оновити існуючий ресурс
- DELETE - видалити ресурс
Нічого не нагадує? Якщо порівняти з SQL-синтаксисом, GET - це запит SELECT, POST - це INSERT, PUT - UPDATE, і DELETE - знову просто DELETE.
Ресурси - це ті дані, з якими ми працюємо. Наприклад у нашому блозі стаття - це ресурс, коментарій - це теж ресурс. Ресурси можуть мати взаємозв'язки, та містити в собі інші ресурси. Для більшості ресурсів в нашому додатку будуть необхідні операції їх створення, отримання, оновлення та видалення.
Крім звичних GET і POST Sinatra розуміє методи PUT і DELETE. Нажаль ці методи не підтримуються броузерами, але Sinatra вміє з ними працювати через прихований елемент форми з ім'ям "_method" і значенням, рівним методу HTTP: put або delete. Наприклад:
<form method="post" action "/destroy">
<input type="hidden" name="_method" value="delete">
<button type="submit">Destroy it</button>
</form>
Далі ми будемо вважати клас-контролер реалізацією інтерфейсу REST.
Наш контролер буде реалізовувати наступні сім дій(методів).
Чотири цих:
- show: обробляє GET запит для відображення індивідуального ресурсу, який ідентифікується виразом params[:id]
- create: обробляє POST запит для створення нового екземпляру ресурсу
- update: обробляє PUT запит для оновлення існуючого ресурсу, ідентифікованого виразом params[:id], використовуючи дані зв'язані з запитом
- destroy: обробляє DELETE запит для видалення екземпляра ресурсу, ідентифікованого виразом params[:id]
І три цих:
- index: обробляє GET запит для відображення колекції ресурсів
- new: обробляє GET запит, який створює логічну структуру нового ресурсу і передає її клієнту. Цей ресурс не буде збережений на сервері. Можна вважати, що дія new створює порожню форму, яка передається клієнту для заповнення.
- edit: обробляє GET запит, який повертає вміст ресурсу, ідентифікованого виразом params[:id], в форму, пристосовану для редагування цього вмісту
Не важко помітити, що ці сім дій включають чотири базових операції для створення, читання, оновлення і видалення ресурсу - CRUD (create, read, update, delete). Серед них також є дії для виводу переліку ресурсів та дві додаткові дії, які повертають клієнту новий та існуючий ресурси в форму, призначену для редагування.
Для Sinatra назви цих дій не мають ніякого значення, і використовуються мною тільки для зручності, і є запозиченими з Rails.
Для того щоб реалізувати REST підхід у нашому додатку треба поступити інакше ніж у попередній статті. В першу чергу один і той же URL може в залежності залежати від типу HTTP запиту відповідати різним методам. Наприклад URL
/posts/1
повинен викликати метод show(для відображення статті №1), якщо був використаний запит GET, але у випадку запиту DELETE повинен викликати метод destroy.Все що нам залишилося зробити, це реалізувати цих сім методів у нашому контролері і оновити шаблони представлень.
blog.rb
# index
get "/posts" do
@posts = Post.all
haml :"posts/index"
end
# new
get "/posts/new" do
haml :"posts/new"
end
# create
post "/posts" do
@post = Post.create(:title => params[:title], :body => params[:body])
if @post.save
redirect "/posts"
else
redirect "/posts/new"
end
end
# show
get "/posts/:id" do
@post = Post.first(:id => params[:id])
haml :"posts/show"
end
# edit
get "/posts/:id/edit" do
@post = Post.first(:id => params[:id])
haml :"posts/edit"
end
# update
put "/posts/:id" do
id = params[:id]
@post = Post.first(:id => params[:id])
if @post.update(:title => params[:title], :body => params[:body])
redirect "/posts/#{id}"
else
redirect "/posts/#{id}/edit"
end
end
# destroy
delete "/posts/:id" do
post = Post.first(:id => params[:id])
post.destroy!
redirect "/posts"
end
index.haml
#header
%h1 Мій блог
%a{:href => "posts/new"}> New Post
#content
- @posts.each do |post|
.container
%h3= post.title
%p= post.body
%p= post.created_at
%table
%tr
%td
%a{:href => "posts/#{post.id}"}> Show
%td
%a{:href => "posts/#{post.id}/edit"}> Edit
%td
%form{:method => 'post', :action => "/posts/#{post.id}"}
%input{:type => "hidden", :name => "_method", :value => "delete"}
%input{:type=>'submit', :value => 'Destroy'}
show.haml
%h3= @post.title
%p= @post.body
%a{:href => "/posts"}= "< Back"
new.haml
%h1 Write a new post
%form{:method => 'post', :action => "/posts"}
%ul
%li#title
%label{:for => 'post_title'} Title:
%br
%input{:type=>'text', :id => 'post_title', :name => 'title'}
%li#body
%label{:for => 'post_body'} Body:
%br
%textarea{:type=>'textarea', :id => 'post_body', :cols => 80, :rows => 5, :name => 'body'}
%input{:type=>'submit', :value => 'New'}
%a{:href => "/posts"}= "< Back"
edit.haml
%h1 Edit a post
%form{:method => 'post', :action => "/posts/#{@post.id}"}
%input{:type => "hidden", :name => "_method", :value => "put"}
%ul
%li#title
%label{:for => 'post_title'} Title:
%br
%input{:type=>'text', :id => 'post_title', :name => 'title', :value => @post.title}
%li#body
%label{:for => 'post_body'} Body:
%br
%textarea{:type=>'textarea', :id => 'post_body', :cols => 80, :rows => 5, :name => 'body'}= @post.body
%input{:type=>'submit', :value => 'Edit'}
%a{:href => "/posts"}= "< Back"
Немає коментарів:
Дописати коментар