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)。


<<:  【Day7】:GPIO输入输出(下)

>>:  Day19-pytorch(2)认识backward、自己设置loss function及updata参数

[day27][後端][实作] 引入Typescipt,webpack的loader(下)

同步发表到驴形笔记 前情题要 在上这一篇中我们成功让webpack可以吃下".ts&qu...

WebAssembly是什么?

Docker 创始人 Solomon Hykes 发布了一条推特在业界引起了轩然大波(见下面的推文)...

DAY11 Kotlin基础 条件语句

国小造句最常见的题目就是:如果...就...,如果被打就会痛。对於程序语言也是有这样的语法给你作使用...

Day 23 - Rancher Fleet 环境架设与介绍

本文将於赛後同步刊登於笔者部落格 有兴趣学习更多 Kubernetes/DevOps/Linux 相...

1.5 Design System - 可以先参考哪些设计系统

「最後的演讲」~ Randy Pausch 这是一本高中体育老师推荐的书,里面有件事影响我蛮多 那...