Application Programming Interface的縮寫,主要在I
,一個接口一個介面,能讓兩個軟體間相互溝通通。
Interface
。其實生活中到處充滿了I
,正在看這篇文章的你,因為電腦這個介面,讓你能讀取到iT邦幫忙
的網頁及其DB
裡的資料。在7-11
點咖啡,店員點用咖啡機上的按鈕,讓咖啡機產生咖啡,那些按鈕就是一個介面。這些介面讓我們能直接操作機器,而不是還要使用者寫一段程式,咖啡機才會磨咖啡。
當專案,不管是用Rails
、Django
、Yii
或任何語言編寫,如果想要有地圖顯示功能,那可能要去串接Map API
,如果是想要能上傳圖片、音樂或影片,那可能要去串接雲端 API
,有這些API
後當網頁送出資料給Map
或雲端
時,他們才會知道你發出的資料是什麼,並做正確處理,當然有的會傳給資料給你,也因為有API
才能轉換成我們專案想要的資料。
無論是因為興趣還是因為要吃飯寫code,總有一天要會寫
當功能越成熟時,總會希望使用者越來越多,但每個使用者的介面也不一定相同,iOS
、Android
、或PC
,為網站建立一個API
能方便讓任何介面的軟體開發者串接,進而使用到網站的功能,在這網路超發達的時代,已經是必要的事了。
API
會不會太殺雞用牛刀?Rails 5 有了only API
模式,API
撰寫目前主流風格是REST API
,就是**Rails
是一個非常RESTful的框架**的那個REST
,圍繞在資源(Resource)來做CRUD的操作,所以使用過Rails
後再以Rails
製作API
非常容易上手。
請注意,我是用API-Only
,如果之後還想回頭做View
會很痛苦!
今天會先做到可以show
與create
,明天完整CRUD
,後天認證
。
$ rails new api-test --api
Git
沒skip的話。$ git add --all
$ git commit -m "Initial commit"
能推上Github
的話也不錯。
API controller
。API
的設計上通常不會用破壞性的方式去增加功能,網路上資料常看到這句話,簡單一點理解,API
是讓其他開發人員串接的,不應該破壞原本功能而去增加新功能,保持靈活性,將功能慢慢往上加,不會突然皆捨去一個功能,也因此常常一開始就會給予版本號。
$ rails g controller api/v1/articles index show --no-test-framework
良好的API
也需要有做test
才對。
適當利用generate
,全手動也是很好,但就失去了用Rails
作API
超方便這點了。
會自動生成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
也可以,之後就解開了。
Model
還有Migration
ˇ檔案。rails g model article title author description
我自己是會慣性檢查Migration
檔案,這邊不秀出來了。
一樣記得。
$ rails db:create
$ rails db:migrate
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,失敗了一點反應都沒有時,會很痛苦。
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
。
畫面瞬間會順眼很多,這邊就不展示了。
雖然沒必要,還是請faker
幫忙吧,不然手打假資料真的好累。
10.times do
Article.create(
title: Faker::Artist.name,
author: Faker::FunnyName.name,
description: Faker::Lorem.sentences)
end
$ rails db:seed
rails s
。正常會有以下畫面。
明天會繼續完成整個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)。