[Day06] 用 .NET 实做简单的 RESTful API

HTTP request
上次我们建立了一个直接能跑的专案,但是它只有一个回传随机天气的 API 接口:WeatherForecastController 的 Get() Action。当我们执行专案,我们在 Swagger 页面可以看到这个接口的资讯GET API

当我们点击这个 API 然後再点 Try it out -> Execute,这个页面就会发出一个 HTTP request 到我们正在执行的 API server。在网站的应用中,HTTP 是最常用来互相沟通的通讯协定,最常用的 request 有

  • GET - 通常用来读取资料
  • POST - 通常用来根据使用者输入的表单新增资料
  • PUT - 通常用来更新资料
  • DELETE - 通常用来删除资料

在这里笔者加上「通常」的原因是,其实我们接到请求之後想要在 controller action 里面做什麽都可以。例如笔者第一份工作时我的 API 只有分 GET 跟 POST,除了读资料以外通通用 POST 处理。当然,这是很不好的示范,看完这篇文章以後,请尽量不要这麽干 XD

HTTP 是一个非常大的主题,想了解细节的邦友可以参考这篇文章,图文并茂,写得详细又好懂。

RESTful API
RESTful API 是一种 API 设计风格,这几年来越来越流行,甚至可以说已经成为主流,因为他直觉又好管理。以前笔者那种「除了 GET 其他全部 POST」的做法,到後面 Controller 里会有一大堆需要读名字才能知道它在做什麽的 action,例如 CreateUser(), UpdateUser, DeleteUser()。网站一大,API 就开始越来越难管理,只好前端跟後端共享一个 API 文件来彼此沟通。

使用 RESTful API 以後,目标主体(User)搭配 HTTP 动词(GET, POST, PUT, DELETE)就能做到我们需要的功能,而 API 接口确变得非常简洁、优雅

  • [HttpGet] localhost:5000/User 就代表跟 API 索取使用者资料
  • [HttpPost] localhost:5000/User 就代表叫 API 新增一个使用者
  • [HttpPut] localhost:5000/User/1 就代表叫 API 更新 ID 为 1 的使用者
  • [HttpDelete] localhost:5000/User/2 叫 API 删除 ID 为 2 的使用者

RESTful API 还有许多优点,也有更多详细的规范,想要了解更多,请参考这篇文章,一样图文并茂,写得详细又好懂。

实作 RESTful API
现在,我们要来实作一个阳春的 RESTful API。首先,我们先来新增负责 API 接口的 Controller,对 Controllers 点右键 -> 新增控制器 -> 选择通用分类下的 API -> 选择执行读取/写入的 API 控制器。然後!Tada~!一个 RESTful 的 Controller 就出现了!Visual Studio 就是这麽香。
https://ithelp.ithome.com.tw/upload/images/20210906/20140664NyA241r4iU.png

接着,新增用来代表使用者的 class。笔者习惯在专案底下新增一个 Models 资料夹,再把代表资料的 class 放在这边:对Models 资料夹点右键 -> 新增类别 -> 写上一些简单的属性
https://ithelp.ithome.com.tw/upload/images/20210906/20140664mMeKtijmxa.png

最後,把回传的资料型态改一改,再把 CRUD (Create, Read, Update, Delete)的程序码加到对应的 Controller Action 就完成了。

[Route("api/[controller]")]
[ApiController]
public class UserController : ControllerBase
{
    private static List<User> _users = new List<User>()
    {
        new User() {UserId = 0, UserName = "Alice", Email="[email protected]"},
        new User() {UserId = 1, UserName = "Bob", Email="[email protected]"},
        new User() {UserId = 2, UserName = "Cathy", Email="[email protected]"},
    };
    
    // GET: api/<UserController>
    [HttpGet]
    public IEnumerable<User> Get()
    {
        return _users;
    }

    // GET api/<UserController>/5
    [HttpGet("{id}")]
    public User Get(int id)
    {
        var user = _users.FirstOrDefault(x => x.UserId == id);
        if (user == null)
        {
            throw new Exception("找不到 user");
        }
        return user;
    }

    // POST api/<UserController>
    [HttpPost]
    public void Post(User user)
    {
        user.UserId = _users.Max(x => x.UserId) + 1;
        _users.Add(user);
    }

    // PUT api/<UserController>/5
    [HttpPut("{id}")]
    public void Put(int id, User newUserData)
    {
        var existingUser = _users.FirstOrDefault(x => x.UserId == id);
        if (existingUser == null)
        {
            throw new Exception("找不到 user");
        }
        existingUser.UserName = newUserData.UserName;
        existingUser.Email = newUserData.Email;
    }

    // DELETE api/<UserController>/5
    [HttpDelete("{id}")]
    public void Delete(int id)
    {
        var existingUser = _users.FirstOrDefault(x => x.UserId == id);
        if (existingUser == null)
        {
            throw new Exception("找不到 user");
        }
        _users.Remove(existingUser);
    }
}

上面的程序码有几个地方要注意:

  1. [Route("api/[controller]")] 指示 .NET 把 Controller 的名字当成路由的一部份,意即要使用这个 Controller 时,URL 要输入 "网址/api/Controller名字/"
  2. [ApiController] 标记了这个 Controller 是 API Controller,会帮我们套用一些预设设定,例如复杂的型别预设是 [FromBody],也就是说,加了 [ApiController] 这个属性之後,原本 PUT action 的 [FromBody] 可以拿掉
  3. 因为目前我们还没有使用资料库,所以偷懒用了一个 static 变数储存资料,这是不好的做法!等到我们开始使用资料库就会把这个换掉
  4. 这里的资料操作使用 LINQ,本系列文会使用 Dapper 操作资料库所以不会特别说明,但是 LINQ 真的是方便又好用,如果有心想写 .NET 诚心建议把它学起来,这里一样推荐一篇 LINQ 的延伸阅读
  5. throw new Exception 也是不好的用法,会让真正出错的 Exception 难以被追踪,我们会在後面的文章改掉

<<:  [30天 Vue学好学满 DAY6] 计算属性(Computed)

>>:  [Day 1] Leetcode 1629. Slowest Key

【这些年我似是非懂的 Javascript】那些年我睡掉的物件导向 #浅谈 #Part 1

嗨~各位好久不见, 最近几乎都在写一些自己喜欢的专案, 不知不觉已经两周了呢 (欢乐的时光总是过得...

[DAY 26] _STM32 看门狗简介_独立看门狗(2)

昨天件绍了看们狗的,今天就来看看如何使用看门狗 独立看门狗一般用来检测和解决由程序引起的故障,比如一...

Progressive Web App Badging API 入门实做 (8)

什麽是 Badging API Badging API 让 App 能够显示通知数字,不过通知数字的...

[Day 01] 纲要

前言 HIYO!又是阿峻我啦~ 不知从何时开始,Deep Learning 跟 AI 这两个名词好像...

Day03 测试写起乃 - 安装Rspec

安装 Rspec 在安装 Rspec 之前我们先产生一个 Rails 6的新专案到 Gemfile ...