ทุกวันนี้ เป็นเรื่องปกติที่ต้องพึ่งพา API (อินเทอร์เฟซการเขียนโปรแกรมแอปพลิเคชัน) เป็นอย่างมาก ไม่เพียงแต่บริการขนาดใหญ่เช่น Facebook และ Twitter เท่านั้นที่ใช้บริการ API ยังได้รับความนิยมอย่างมากเนื่องจากมีการแพร่กระจายของเฟรมเวิร์กฝั่งไคลเอ็นต์ เช่น React, Angular และอื่นๆ อีกมากมาย Ruby on Rails กำลังติดตามแนวโน้มนี้ และเวอร์ชันล่าสุดนำเสนอคุณลักษณะใหม่ที่ช่วยให้คุณสร้างแอปพลิเคชันเฉพาะ API ได้
ในขั้นต้น ฟังก์ชันนี้ถูกรวมไว้ใน gem แยกต่างหากที่เรียกว่า rails-api แต่ตั้งแต่มีการเปิดตัว Rails 5 ตอนนี้ก็เป็นส่วนหนึ่งของแกนหลักของเฟรมเวิร์กแล้ว ฟีเจอร์นี้ร่วมกับ ActionCable นั้นน่าจะได้รับการคาดหวังมากที่สุด ดังนั้นวันนี้เราจะมาพูดถึงเรื่องนี้กัน
บทความนี้ครอบคลุมถึงวิธีสร้างแอปพลิเคชัน Rails เฉพาะ API และอธิบายวิธีจัดโครงสร้างเส้นทางและตัวควบคุม ตอบกลับด้วยรูปแบบ JSON เพิ่มซีเรียลไลเซอร์ และตั้งค่า CORS (การแชร์ทรัพยากรข้ามต้นทาง) คุณจะได้เรียนรู้เกี่ยวกับตัวเลือกบางอย่างในการรักษาความปลอดภัย API และปกป้องจากการละเมิด
แหล่งที่มาของบทความนี้มีอยู่ที่ GitHub
การสร้างแอปพลิเคชันเฉพาะ API
ในการเริ่มต้น ให้รันคำสั่งต่อไปนี้:
rails new RailsApiDemo --api
กำลังจะสร้างแอปพลิเคชัน Rails เฉพาะ API ใหม่ชื่อ RailsApiDemo . อย่าลืมว่าการรองรับ --api เพิ่มตัวเลือกใน Rails 5 เท่านั้น ดังนั้นตรวจสอบให้แน่ใจว่าคุณได้ติดตั้งเวอร์ชันนี้หรือเวอร์ชันที่ใหม่กว่าแล้ว
เปิด Gemfile และสังเกตว่ามันเล็กกว่าปกติมาก:อัญมณีอย่าง coffee-rails , turbolinks , และ sass-rails หายไปแล้ว
ไฟล์ config/application.rb ไฟล์มีบรรทัดใหม่:
config.api_only = true
หมายความว่า Rails จะโหลดมิดเดิลแวร์ชุดที่เล็กกว่า เช่น ไม่รองรับคุกกี้และเซสชัน นอกจากนี้ หากคุณพยายามสร้างโครงนั่งร้าน มุมมองและสินทรัพย์จะไม่ถูกสร้างขึ้น ที่จริงแล้ว หากคุณตรวจสอบ มุมมอง/เลย์เอาต์ ไดเรกทอรี คุณจะสังเกตเห็นว่า application.html.erb ไฟล์ก็หายไปเช่นกัน
ความแตกต่างที่สำคัญอีกประการหนึ่งคือ ApplicationController สืบทอดมาจาก ActionController::API ไม่ใช่ ActionController::Base .
เกือบแล้ว ทั้งหมดนี้เป็นแอปพลิเคชัน Rails พื้นฐานที่คุณเคยเห็นมาหลายครั้งแล้ว ตอนนี้ มาเพิ่มโมเดลสองสามแบบเพื่อให้เรามีบางอย่างที่จะใช้งาน:
rails g model User name:string rails g model Post title:string body:text user:belongs_to rails db:migrate
ไม่มีอะไรแฟนซีเกิดขึ้นที่นี่:โพสต์ที่มีชื่อและเนื้อหาเป็นของผู้ใช้
ตรวจสอบให้แน่ใจว่าได้ตั้งค่าการเชื่อมโยงที่เหมาะสมและให้การตรวจสอบการตรวจสอบอย่างง่าย:
รุ่น/user.rb
has_many :posts validates :name, presence: true
รุ่น/post.rb
belongs_to :user validates :title, presence: true validates :body, presence: true
ฉลาดหลักแหลม! ขั้นตอนต่อไปคือการโหลดระเบียนตัวอย่างสองสามรายการลงในตารางที่สร้างขึ้นใหม่
กำลังโหลดข้อมูลสาธิต
วิธีที่ง่ายที่สุดในการโหลดข้อมูลบางส่วนคือการใช้ seeds.rb ไฟล์ภายใน db ไดเรกทอรี อย่างไรก็ตาม ฉันขี้เกียจ (อย่างที่โปรแกรมเมอร์หลายคนเป็น) และไม่อยากนึกถึงเนื้อหาตัวอย่างใดๆ ดังนั้น ทำไมเราไม่ใช้ประโยชน์จากอัญมณีปลอมที่สามารถสร้างข้อมูลแบบสุ่มได้หลายประเภท:ชื่อ อีเมล คำฮิปสเตอร์ ข้อความ "lorem ipsum" และอีกมากมาย
Gemfile
group :development do
gem 'faker'
end ติดตั้งอัญมณี:
bundle install
ตอนนี้ปรับแต่ง seeds.rb :
db/seeds.rb
5.times do
user = User.create({name: Faker::Name.name})
user.posts.create({title: Faker::Book.title, body: Faker::Lorem.sentence})
end สุดท้าย โหลดข้อมูลของคุณ:
rails db:seed
ตอบสนองด้วย JSON
แน่นอนว่าตอนนี้ เราต้องการเส้นทางและตัวควบคุมบางตัวเพื่อสร้าง API ของเรา เป็นเรื่องปกติที่จะซ้อนเส้นทางของ API ไว้ใต้ api/ เส้นทาง. นอกจากนี้ นักพัฒนามักจะระบุเวอร์ชันของ API ในพาธ เช่น api/v1/ . ในภายหลัง หากจำเป็นต้องทำการเปลี่ยนแปลงบางอย่าง คุณสามารถสร้างเนมสเปซใหม่ (v2 ) และตัวควบคุมแยกต่างหาก
นี่คือลักษณะเส้นทางของคุณ:
config/routes.rb
namespace 'api' do
namespace 'v1' do
resources :posts
resources :users
end
end สิ่งนี้สร้างเส้นทางเช่น:
api_v1_posts GET /api/v1/posts(.:format) api/v1/posts#index
POST /api/v1/posts(.:format) api/v1/posts#create
api_v1_post GET /api/v1/posts/:id(.:format) api/v1/posts#show
คุณสามารถใช้ scope เมธอดแทน namespace แต่โดยค่าเริ่มต้นแล้ว มันจะมองหา UsersController และ PostsController ภายใน คอนโทรลเลอร์ ไดเร็กทอรี ไม่ใช่ใน controllers/api/v1 , ดังนั้นจงระวัง.
สร้าง api โฟลเดอร์ที่มีไดเร็กทอรีซ้อน v1 ภายใน คอนโทรลเลอร์ . เติมข้อมูลด้วยตัวควบคุมของคุณ:
controllers/api/v1/users_controller.rb
module Api
module V1
class UsersController < ApplicationController
end
end
end controllers/api/v1/posts_controller.rb
module Api
module V1
class PostsController < ApplicationController
end
end
end
โปรดทราบว่าคุณไม่เพียงแต่ต้องซ้อนไฟล์ของคอนโทรลเลอร์ไว้ใต้ api/v1 เส้นทาง แต่ตัวคลาสเองจะต้องถูกเนมสเปซภายใน Api และ V1 โมดูล
คำถามต่อไปคือจะตอบสนองอย่างไรกับข้อมูลที่จัดรูปแบบ JSON อย่างถูกต้อง ในบทความนี้ เราจะลองใช้วิธีแก้ปัญหาเหล่านี้:jBuilder และ active_model_serializers gems ดังนั้นก่อนที่จะไปยังส่วนถัดไป ให้วางลงใน Gemfile :
Gemfile
gem 'jbuilder', '~> 2.5' gem 'active_model_serializers', '~> 0.10.0'
จากนั้นเรียกใช้:
bundle install
การใช้ jBuilder Gem
jBuilder เป็นอัญมณียอดนิยมที่ดูแลโดยทีมงาน Rails ซึ่งมี DSL แบบง่าย (ภาษาเฉพาะโดเมน) ช่วยให้คุณกำหนดโครงสร้าง JSON ในมุมมองของคุณได้
สมมติว่าเราต้องการแสดงโพสต์ทั้งหมดเมื่อผู้ใช้กด index การกระทำ:
controllers/api/v1/posts_controller.rb
def index
@posts = Post.order('created_at DESC')
end สิ่งที่คุณต้องทำคือสร้างมุมมองที่ตั้งชื่อตามการกระทำที่เกี่ยวข้องกับ .json.jbuilder การขยาย. โปรดทราบว่ามุมมองต้องอยู่ใต้ api/v1 เส้นทางเช่นกัน:
views/api/v1/posts/index.json.jbuilder
json.array! @posts do |post| json.id post.id json.title post.title json.body post.body end
json.array! ข้าม @posts อาร์เรย์ json.id , json.title และ json.body สร้างคีย์ด้วยชื่อที่สอดคล้องกันซึ่งตั้งค่าอาร์กิวเมนต์เป็นค่า หากคุณไปที่ http://localhost:3000/api/v1/posts.json คุณจะเห็นผลลัพธ์ที่คล้ายกับผลลัพธ์นี้:
[
{"id": 1, "title": "Title 1", "body": "Body 1"},
{"id": 2, "title": "Title 2", "body": "Body 2"}
] จะเป็นอย่างไรถ้าเราต้องการแสดงผู้เขียนสำหรับแต่ละโพสต์ด้วย มันง่าย:
json.array! @posts do |post|
json.id post.id
json.title post.title
json.body post.body
json.user do
json.id post.user.id
json.name post.user.name
end
end ผลลัพธ์จะเปลี่ยนเป็น:
[
{"id": 1, "title": "Title 1", "body": "Body 1", "user": {"id": 1, "name": "Username"}}
] เนื้อหาของ .jbuilder ไฟล์เป็นรหัส Ruby ธรรมดา คุณจึงสามารถใช้การทำงานพื้นฐานทั้งหมดได้ตามปกติ
โปรดทราบว่า jBuilder รองรับบางส่วนเช่นเดียวกับมุมมอง Rails ทั่วไป ดังนั้นคุณอาจพูดว่า:
json.partial! partial: 'posts/post', collection: @posts, as: :post
แล้วสร้าง views/api/v1/posts/_post.json.jbuilder ไฟล์ที่มีเนื้อหาดังต่อไปนี้:
json.id post.id
json.title post.title
json.body post.body
json.user do
json.id post.user.id
json.name post.user.name
end อย่างที่คุณเห็น jBuilder นั้นง่ายและสะดวก อย่างไรก็ตาม คุณอาจยึดติดกับซีเรียลไลเซอร์แทนได้ ดังนั้นเรามาพูดถึงมันในหัวข้อถัดไป
การใช้ซีเรียลไลเซอร์
rails_model_serializers gem สร้างขึ้นโดยทีมที่เริ่มจัดการ rails-api ตามที่ระบุไว้ในเอกสารประกอบ rails_model_serializers นำคอนฟิกูเรชันเหนือการกำหนดค่ามาสู่รุ่น JSON ของคุณ โดยพื้นฐานแล้ว คุณกำหนดว่าควรใช้ฟิลด์ใดในการทำให้เป็นอันดับ (นั่นคือ การสร้าง JSON)
นี่คือซีเรียลไลเซอร์ตัวแรกของเรา:
serializers/post_serializer.rb
class PostSerializer < ActiveModel::Serializer attributes :id, :title, :body end
ที่นี่เราบอกว่าทุกฟิลด์เหล่านี้ควรมีอยู่ใน JSON ที่เป็นผลลัพธ์ ตอนนี้วิธีการต่างๆ เช่น to_json และ as_json การเรียกใช้โพสต์จะใช้การกำหนดค่านี้และส่งคืนเนื้อหาที่เหมาะสม
หากต้องการดูการทำงานจริง ให้แก้ไข index การกระทำเช่นนี้:
controllers/api/v1/posts_controller.rb
def index
@posts = Post.order('created_at DESC')
render json: @posts
end
as_json จะถูกเรียกโดยอัตโนมัติเมื่อ @posts วัตถุ
แล้วผู้ใช้ล่ะ? Serializers ช่วยให้คุณระบุความสัมพันธ์ได้เช่นเดียวกับตัวแบบ ยิ่งไปกว่านั้น Serializers สามารถซ้อนกันได้:
serializers/post_serializer.rb
class PostSerializer < ActiveModel::Serializer
attributes :id, :title, :body
belongs_to :user
class UserSerializer < ActiveModel::Serializer
attributes :id, :name
end
end
ตอนนี้ เมื่อคุณทำให้โพสต์เป็นอนุกรม จะมี user . ที่ซ้อนกันโดยอัตโนมัติ คีย์พร้อมรหัสและชื่อ หากในภายหลังคุณสร้าง serializer แยกต่างหากสำหรับผู้ใช้ด้วย :id ไม่รวมแอตทริบิวต์:
serializers/post_serializer.rb
class UserSerializer < ActiveModel::Serializer
attributes :name
end
แล้ว @user.as_json จะไม่ส่งคืน ID ผู้ใช้ ยัง @post.as_json จะส่งคืนทั้งชื่อผู้ใช้และ ID ของผู้ใช้ ดังนั้นโปรดจำไว้
การรักษาความปลอดภัยของ API
ในหลายกรณี เราไม่ต้องการให้ใครดำเนินการใดๆ โดยใช้ API เรามานำเสนอการตรวจสอบความปลอดภัยอย่างง่าย และบังคับให้ผู้ใช้ของเราส่งโทเค็นของพวกเขาเมื่อสร้างและลบโพสต์
โทเค็นจะมีอายุการใช้งานไม่จำกัดและสร้างขึ้นเมื่อลงทะเบียนของผู้ใช้ ก่อนอื่น เพิ่ม token . ใหม่ ไปที่ user ตาราง:
rails g migration add_token_to_users token:string:index
ดัชนีนี้ควรรับประกันความเป็นเอกลักษณ์ เนื่องจากไม่มีผู้ใช้สองคนที่มีโทเค็นเดียวกัน:
db/migrate/xyz_add_token_to_users.rb
add_index :users, :token, unique: true
ใช้การย้ายข้อมูล:
rails db:migrate
ตอนนี้เพิ่ม before_save โทรกลับ:
รุ่น/user.rb
before_create -> {self.token = generate_token}
generate_token วิธีส่วนตัวจะสร้างโทเค็นในวงจรที่ไม่มีที่สิ้นสุดและตรวจสอบว่าเป็นเอกลักษณ์หรือไม่ ทันทีที่พบโทเค็นที่ไม่ซ้ำกัน ให้ส่งคืน:
รุ่น/user.rb
private
def generate_token
loop do
token = SecureRandom.hex
return token unless User.exists?({token: token})
end
end คุณสามารถใช้อัลกอริธึมอื่นเพื่อสร้างโทเค็นได้ ตัวอย่างเช่น ตามแฮช MD5 ของชื่อผู้ใช้และเกลือบางส่วน
การลงทะเบียนผู้ใช้
แน่นอน เราจำเป็นต้องอนุญาตให้ผู้ใช้ลงทะเบียนด้วย เพราะไม่เช่นนั้นพวกเขาจะไม่สามารถรับโทเค็นได้ ฉันไม่ต้องการแนะนำมุมมอง HTML ใด ๆ ในแอปพลิเคชันของเรา ให้เพิ่มวิธีการ API ใหม่แทน:
controllers/api/v1/users_controller.rb
def create
@user = User.new(user_params)
if @user.save
render status: :created
else
render json: @user.errors, status: :unprocessable_entity
end
end
private
def user_params
params.require(:user).permit(:name)
end
เป็นความคิดที่ดีที่จะส่งคืนรหัสสถานะ HTTP ที่มีความหมาย เพื่อให้นักพัฒนาเข้าใจว่าเกิดอะไรขึ้น ตอนนี้ คุณอาจให้ซีเรียลไลเซอร์ใหม่สำหรับผู้ใช้ หรือติด .json.jbuilder ไฟล์. ฉันชอบรูปแบบหลังมากกว่า (นั่นเป็นสาเหตุที่ฉันไม่ส่ง :json ตัวเลือกในการ render วิธี) แต่คุณสามารถเลือกวิธีใดก็ได้ อย่างไรก็ตาม โปรดทราบว่าโทเค็น ต้องไม่ จัดลำดับเสมอ เช่น เมื่อคุณส่งคืนรายชื่อผู้ใช้ทั้งหมด ข้อมูลดังกล่าวควรได้รับการดูแลอย่างปลอดภัย!
views/api/v1/users/create.json.jbuilder
json.id @user.id json.name @user.name json.token @user.token
ขั้นตอนต่อไปคือการทดสอบว่าทุกอย่างทำงานอย่างถูกต้องหรือไม่ คุณสามารถใช้ curl คำสั่งหรือเขียนโค้ด Ruby เนื่องจากบทความนี้เกี่ยวกับ Ruby ฉันจะใช้ตัวเลือกการเข้ารหัส
การทดสอบการลงทะเบียนของผู้ใช้
ในการดำเนินการคำขอ HTTP เราจะใช้ Faraday gem ซึ่งมีอินเทอร์เฟซทั่วไปมากกว่าอะแดปเตอร์จำนวนมาก (ค่าเริ่มต้นคือ Net::HTTP ). สร้างไฟล์ Ruby แยกต่างหาก รวม Faraday และตั้งค่าไคลเอนต์:
api_client.rb
require 'faraday'
client = Faraday.new(url: 'http://localhost:3000') do |config|
config.adapter Faraday.default_adapter
end
response = client.post do |req|
req.url '/api/v1/users'
req.headers['Content-Type'] = 'application/json'
req.body = '{ "user": {"name": "test user"} }'
end
ตัวเลือกทั้งหมดเหล่านี้อธิบายได้ง่าย:เราเลือกอะแดปเตอร์เริ่มต้น ตั้งค่า URL คำขอเป็น http://localhost:300/api/v1/users เปลี่ยนประเภทเนื้อหาเป็น application/json และจัดเตรียมเนื้อหาของคำขอของเรา
การตอบสนองของเซิร์ฟเวอร์จะมี JSON ดังนั้นในการแยกวิเคราะห์ ฉันจะใช้ Oj gem:
api_client.rb
require 'oj' # client here... puts Oj.load(response.body) puts response.status
นอกจากการตอบกลับที่แยกวิเคราะห์แล้ว ฉันยังแสดงรหัสสถานะเพื่อจุดประสงค์ในการดีบัก
ตอนนี้คุณสามารถเรียกใช้สคริปต์นี้:
ruby api_client.rb
และเก็บโทเค็นที่ได้รับไว้ที่ไหนสักแห่ง เราจะใช้ในส่วนถัดไป
ตรวจสอบสิทธิ์ด้วยโทเค็น
ในการบังคับใช้การตรวจสอบโทเค็น authenticate_or_request_with_http_token สามารถใช้วิธีการ เป็นส่วนหนึ่งของโมดูล ActionController::HttpAuthentication::Token::ControllerMethods ดังนั้นอย่าลืมรวมไว้ด้วย:
controllers/api/v1/posts_controller.rb
class PostsController < ApplicationController
include ActionController::HttpAuthentication::Token::ControllerMethods
# ...
end
เพิ่ม before_actionใหม่ และวิธีการที่เกี่ยวข้อง:
controllers/api/v1/posts_controller.rb
before_action :authenticate, only: [:create, :destroy]
# ...
private
# ...
def authenticate
authenticate_or_request_with_http_token do |token, options|
@user = User.find_by(token: token)
end
end ตอนนี้ หากไม่ได้ตั้งค่าโทเค็นหรือหากไม่พบผู้ใช้ที่มีโทเค็นดังกล่าว ข้อผิดพลาด 401 จะถูกส่งคืน เป็นการหยุดการดำเนินการจากการดำเนินการ
โปรดทราบว่าการสื่อสารระหว่างไคลเอนต์และเซิร์ฟเวอร์ต้องทำผ่าน HTTPS เพราะไม่เช่นนั้นโทเค็นอาจถูกปลอมแปลงได้ง่าย แน่นอนว่าโซลูชันที่ให้มานั้นไม่เหมาะ และในหลายกรณี ควรใช้โปรโตคอล OAuth 2 สำหรับการตรวจสอบสิทธิ์ มีอัญมณีอย่างน้อย 2 ชิ้นที่ช่วยให้กระบวนการสนับสนุนคุณลักษณะนี้ง่ายขึ้นอย่างมาก ได้แก่ Doorkeeper และ oPRO
การสร้างโพสต์
หากต้องการดูการตรวจสอบความถูกต้องของเรา ให้เพิ่ม create การดำเนินการกับ PostsController :
controllers/api/v1/posts_controller.rb
def create
@post = @user.posts.new(post_params)
if @post.save
render json: @post, status: :created
else
render json: @post.errors, status: :unprocessable_entity
end
end
เราใช้ประโยชน์จาก serializer ที่นี่เพื่อแสดง JSON ที่เหมาะสม @user ถูกกำหนดไว้แล้วใน before_action .
ตอนนี้ทดสอบทุกอย่างโดยใช้โค้ดง่ายๆ นี้:
api_client.rb
client = Faraday.new(url: 'http://localhost:3000') do |config|
config.adapter Faraday.default_adapter
config.token_auth('127a74dbec6f156401b236d6cb32db0d')
end
response = client.post do |req|
req.url '/api/v1/posts'
req.headers['Content-Type'] = 'application/json'
req.body = '{ "post": {"title": "Title", "body": "Text"} }'
end
แทนที่อาร์กิวเมนต์ที่ส่งผ่านไปยัง token_auth ด้วยโทเค็นที่ได้รับเมื่อลงทะเบียนและเรียกใช้สคริปต์
ruby api_client.rb
การลบโพสต์
การลบโพสต์ทำได้ในลักษณะเดียวกัน เพิ่ม destroy การกระทำ:
controllers/api/v1/posts_controller.rb
def destroy
@post = @user.posts.find_by(params[:id])
if @post
@post.destroy
else
render json: {post: "not found"}, status: :not_found
end
end เราอนุญาตให้ผู้ใช้ทำลายโพสต์ที่พวกเขาเป็นเจ้าของจริงเท่านั้น หากลบโพสต์สำเร็จ รหัสสถานะ 204 (ไม่มีเนื้อหา) จะถูกส่งคืน หรือคุณอาจตอบกลับด้วยรหัสของโพสต์ที่ถูกลบไปเนื่องจากจะยังอยู่ในหน่วยความจำ
นี่คือโค้ดสำหรับทดสอบฟีเจอร์ใหม่นี้:
api_client.rb
response = client.delete do |req| req.url '/api/v1/posts/6' req.headers['Content-Type'] = 'application/json' end
แทนที่ ID ของโพสต์ด้วยหมายเลขที่เหมาะกับคุณ
ตั้งค่า CORS
หากคุณต้องการเปิดใช้งานบริการเว็บอื่นๆ เพื่อเข้าถึง API ของคุณ (จากฝั่งไคลเอ็นต์) คุณควรตั้งค่า CORS (Cross-Origin Resource Sharing) อย่างเหมาะสม โดยทั่วไป CORS อนุญาตให้เว็บแอปพลิเคชันส่งคำขอ AJAX ไปยังบริการของบุคคลที่สาม โชคดีที่มีอัญมณีที่เรียกว่า rack-cors ที่ช่วยให้เราสามารถตั้งค่าทุกอย่างได้อย่างง่ายดาย เพิ่มลงใน Gemfile :
Gemfile
gem 'rack-cors'
ติดตั้ง:
bundle install
จากนั้นจัดเตรียมการกำหนดค่าภายใน config/initializers/cors.rb ไฟล์. อันที่จริง ไฟล์นี้ถูกสร้างขึ้นสำหรับคุณแล้วและมีตัวอย่างการใช้งาน นอกจากนี้คุณยังสามารถค้นหาเอกสารที่มีรายละเอียดสวย ๆ ได้ในหน้าของอัญมณี
ตัวอย่างเช่น การกำหนดค่าต่อไปนี้จะอนุญาตให้ทุกคนเข้าถึง API ของคุณโดยใช้วิธีการใดก็ได้:
config/initializers/cors.rb
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins '*'
resource '/api/*',
headers: :any,
methods: [:get, :post, :put, :patch, :delete, :options, :head]
end
end การป้องกันการใช้ในทางที่ผิด
สิ่งสุดท้ายที่ฉันจะพูดถึงในคู่มือนี้คือวิธีการปกป้อง API ของคุณจากการละเมิดและการปฏิเสธการโจมตีบริการ มีอัญมณีที่ดีที่เรียกว่า rack-attack (สร้างโดยผู้คนจาก Kickstarter) ที่ให้คุณขึ้นบัญชีดำหรือไคลเอนต์ที่อนุญาตพิเศษ ป้องกันไม่ให้เซิร์ฟเวอร์ล้นด้วยคำขอ และอื่นๆ อีกมากมาย
วางอัญมณีลงใน Gemfile :
Gemfile
gem 'rack-attack'
ติดตั้ง:
bundle install
จากนั้นให้กำหนดค่าภายใน rack_attack.rb ไฟล์เริ่มต้น เอกสารประกอบของ gem แสดงรายการตัวเลือกทั้งหมดที่มีและแนะนำกรณีการใช้งานบางกรณี นี่คือตัวอย่างการกำหนดค่าที่จำกัดไม่ให้ทุกคนยกเว้นคุณเข้าถึงบริการและจำกัดจำนวนคำขอสูงสุดที่ 5 ต่อวินาที:
config/initializers/rack_attack.rb
class Rack::Attack
safelist('allow from localhost') do |req|
# Requests are allowed if the return value is truthy
'127.0.0.1' == req.ip || '::1' == req.ip
end
throttle('req/ip', :limit => 5, :period => 1.second) do |req|
req.ip
end
end อีกสิ่งหนึ่งที่ต้องทำคือการรวม RackAttack เป็นมิดเดิลแวร์:
config/application.rb
config.middleware.use Rack::Attack
บทสรุป
เรามาถึงจุดสิ้นสุดของบทความนี้แล้ว หวังว่าตอนนี้คุณจะรู้สึกมั่นใจมากขึ้นเกี่ยวกับการสร้าง API ด้วย Rails! โปรดทราบว่านี่ไม่ใช่ตัวเลือกเดียวที่มี—อีกวิธีหนึ่งที่ได้รับความนิยมซึ่งมีมาระยะหนึ่งคือเฟรมเวิร์กของ Grape ดังนั้นคุณอาจสนใจลองดูเช่นกัน
อย่าลังเลที่จะโพสต์คำถามของคุณหากมีบางสิ่งที่ดูเหมือนไม่ชัดเจนสำหรับคุณ ฉันขอขอบคุณที่อยู่กับฉัน และขอให้สนุกกับการเขียนโค้ด!