Computer >> คอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

การสร้าง API ด้วย Rails

ทุกวันนี้ เป็นเรื่องปกติที่ต้องพึ่งพา 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 สร้างคีย์ด้วยชื่อที่สอดคล้องกันซึ่งตั้งค่าอาร์กิวเมนต์เป็นค่า หากคุณไปที่ https://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: 'https://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 คำขอเป็น https://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: 'https://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 ดังนั้นคุณอาจสนใจลองดูเช่นกัน

อย่าลังเลที่จะโพสต์คำถามของคุณหากมีบางสิ่งที่ดูเหมือนไม่ชัดเจนสำหรับคุณ ฉันขอขอบคุณที่อยู่กับฉัน และขอให้สนุกกับการเขียนโค้ด!