iT邦幫忙

2021 iThome 鐵人賽

DAY 21
0
自我挑戰組

初級紅寶石魔法師心得分享。系列 第 21

D-9. Rails API-Only 實作 && House Robber

API

Application Programming Interface的縮寫,主要在I,一個接口一個介面,能讓兩個軟體間相互溝通通。

先認識Interface

其實生活中到處充滿了I,正在看這篇文章的你,因為電腦這個介面,讓你能讀取到iT邦幫忙的網頁及其DB裡的資料。在7-11點咖啡,店員點用咖啡機上的按鈕,讓咖啡機產生咖啡,那些按鈕就是一個介面。這些介面讓我們能直接操作機器,而不是還要使用者寫一段程式,咖啡機才會磨咖啡。

為何需要API?

當專案,不管是用RailsDjangoYii或任何語言編寫,如果想要有地圖顯示功能,那可能要去串接Map API,如果是想要能上傳圖片、音樂或影片,那可能要去串接雲端 API,有這些API後當網頁送出資料給Map雲端時,他們才會知道你發出的資料是什麼,並做正確處理,當然有的會傳給資料給你,也因為有API才能轉換成我們專案想要的資料。

為何需要寫API?

無論是因為興趣還是因為要吃飯寫code,總有一天要會寫
當功能越成熟時,總會希望使用者越來越多,但每個使用者的介面也不一定相同,iOSAndroid、或PC,為網站建立一個API能方便讓任何介面的軟體開發者串接,進而使用到網站的功能,在這網路超發達的時代,已經是必要的事了。

用Rails寫API會不會太殺雞用牛刀?

Rails 5 有了only API模式,API撰寫目前主流風格是REST API,就是**Rails是一個非常RESTful的框架**的那個REST,圍繞在資源(Resource)來做CRUD的操作,所以使用過Rails後再以Rails製作API非常容易上手。


從零練習個最簡單的 WEB API 吧。

請注意,我是用API-Only,如果之後還想回頭做View會很痛苦!

今天會先做到可以showcreate,明天完整CRUD,後天認證

1.建立專案

$ rails new api-test --api

2.來建立一下版控吧,Git沒skip的話。

$ git add --all
$ git commit -m "Initial commit"

能推上Github的話也不錯。


3.產生API controller

API的設計上通常不會用破壞性的方式去增加功能,網路上資料常看到這句話,簡單一點理解,API是讓其他開發人員串接的,不應該破壞原本功能而去增加新功能,保持靈活性,將功能慢慢往上加,不會突然皆捨去一個功能,也因此常常一開始就會給予版本號。

$ rails g controller api/v1/articles index show --no-test-framework

良好的API也需要有做test才對。
適當利用generate,全手動也是很好,但就失去了用RailsAPI超方便這點了。

檢查一下。

會自動生成app/controllers/api/v1這個資料夾。裡面有articles_controller.rb這個檔案。

class Api::V1::ArticlesController < ApplicationController
  def index
  end

  def show
  end
end

config/routes.rb會自動有以下內容。

Rails.application.routes.draw do
  namespace :api do
    namespace :v1 do
      get 'articles/index'
      get 'articles/show'
    end
  end
end

修改一下routes.rb

少一個create

Rails.application.routes.draw do
  namespace :api do
    namespace :v1 do
      resources :articles, only: [:index, :show, :create]
    end
  end
end

其實不only也可以,之後就解開了。


4.建立Model還有Migrationˇ檔案。

rails g model article title author description 

我自己是會慣性檢查Migration檔案,這邊不秀出來了。
一樣記得。

$ rails db:create
$ rails db:migrate

5.開始寫controller內容。

就跟CRUD流程差不多,這邊就不一步一步分開操作了,會直接show寫好的code。
如果真的有萌新參考到這篇文章,請記得自己手動打,3Q。
關於CRUD,搬出初學神書為你自己學Ruby on Rails

class Api::V1::ArticlesController < ApplicationController
  before_action :find_article, only: [:show]

  #GET
  def index
    @articles = Article.all
    render json:@articles, status: 200
  end

  #GET
  def show
    begin @article
      render json: @article, status: 200
    rescue
      render json: {error: "article not found!"}
    end
  end

  #POST
  def create
    @article = Article.new(article_params)
      if @article.save
        render json: @article, status: 200
      else
        render json: {erroe: "create failed"}
      end
  end

  private
  def find_article
    @article = Article.find(params[:id])
  end

  def article_params
    params.require(:article).permit(
      :title,
      :author,
      :description
    )
  end
end

真的是CRUD
不過可以盡量要回傳訊息,尤其是失敗,當自己在串別人API,失敗了一點反應都沒有時,會很痛苦。


6.先在IRB測試一下吧。

拖一下台錢,其實可以直接請seed建立資料了。

2.7.3 :001 > test_date = Article.new(title: "第一個故事", author: "nauosika", description: "今天從零開始學寫API, 好興奮呀! 興奮到模糊!")
 => #<Article id: nil, title: "第一個故事", author: "nauosika", description: "今天從零開始學寫API, ...
2.7.3 :002 > test_date.save
  TRANSACTION (0.3ms)  BEGIN
  Article Create (6.9ms)  INSERT INTO "articles" ("title", "author", "description", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id"  [["title", "第一個故事"], ["author", "nauosika"], ["description", "今天從零開始學寫API, 好興奮呀! 興奮到模糊!"], ["created_at", "2021-09-15 13:37:38.702287"], ["updated_at", "2021-09-15 13:37:38.702287"]]
  TRANSACTION (5.5ms)  COMMIT
 => true
2.7.3 :003 > test_date
 => #<Article id: 1, title: "第一個故事", author: "nauosika", description: "今天從零開始學寫API, 好興奮呀! 興奮到模糊!", created_at: "2021-09-15 13:37:38.702287000 +0000", updated_at: "2021-09-15 13:37:38.702287000 +0000">

好的第一小步確定完成了,專案已經可以正常建立資料。


rails s後,其實這樣已經可以看到資料了,但由於用api only模式,非常....不好看。

如果是用chrome可以接安裝擴充功能JSON Formatter
畫面瞬間會順眼很多,這邊就不展示了。


7.多建立一點資料。

雖然沒必要,還是請faker幫忙吧,不然手打假資料真的好累。

10.times do
  Article.create(
    title: Faker::Artist.name,
    author: Faker::FunnyName.name,
    description: Faker::Lorem.sentences)
end

$ rails db:seed

8.rails s

正常會有以下畫面。

https://ithelp.ithome.com.tw/upload/images/20210921/20135887ecMIZIeI8I.png

明天會繼續完成整個CRUD,以及利用Postman來操作。


今天的leetcode198. House Robber
題目連結:https://leetcode.com/problems/house-robber/
題目重點:指針題。
如果不能連續拿兩間的錢,那就看從中間一點的房子往前看,不拿隔壁那間,看前兩間誰多,拿錢多那間,一直由此模式
紀錄就不會觸發警報了,最後拿紀錄最高的那間。

  $              #第一間左邊沒人,不做紀錄。
[ 2, 7, 9, 3, 1 ]


     $           #第二間左邊有人,但鄰居隔壁沒有兩間作比較,不做紀錄。
[ 2, 7, 9, 3, 1 ]


        $        #第三間左邊有人,但鄰居隔壁只有一間2作比較,那就記錄+2下來。
[ 2, 7, 9, 3, 1 ]
       11        # 9 + 2 = 11 , num[2] += num[0]


           $     #第四間鄰居隔壁有兩間7與2作比較,那就記錄+7下來。
[ 2, 7, 9, 3, 1 ]
       11 10     # 3 + 7  = 10, 

              $  #第五間鄰居隔壁有兩間11與7作比較,那就記錄+11下來。
[ 2, 7, 9, 3, 1 ]
       11 10  12   # 1 + 11  = 12, 


原本打算由nums[2],也就是9開始跑迴圈,但是無法滿足要做鄰居隔壁兩間作比較這件事。

 nums[i] += [num[i - 2], num[ i - 3]].min #i = 2 時不成立。

那就2那間,前面多給一間0的就好了。

2.7.3 :234 > [2,7,9,3,1].unshift(0)
 => [0, 2, 7, 9, 3, 1]

這樣由9開始時。

nums[i] += [num[i - 2], num[ i - 3]].min #成立
# @param {Integer[]} nums
# @return {Integer}
def rob(nums)
  nums.unshift(0)
  (3..(nums.size - 1)).each do |i|
    nums[i] += [nums[i-2], nums[i-3]].max
  end
  nums.max
end

這樣就ok了,(3..(nums.size - 1))覺得太醜可以改`(3...nums.size)。


上一篇
D-10.Rails N+1 queries and kill N+1
下一篇
D-8. Rails 用Postman測試自己的WEB API && Valid Parentheses
系列文
初級紅寶石魔法師心得分享。30

尚未有邦友留言

立即登入留言