昨天使用了 Scaffolding 自動產生 Web API 控制器的動作方法,可以對地址(Address)物件做新增、修改、刪除,以及查詢的動作,今天就來一面深入查看這些工具自動產生的程式碼的內容,並實際操作體驗和測試這些,新增、修改、刪除,查詢的功能是否可以正常運作。
Postman 測試 Web API 的利器
雖然目前寫好的 Web API 已有與住址相關資料的 CRUD (Create、Read、Update、Delete)功能可供操作測試,但是前端的使用者介面還沒有實作完成,而有必要找尋一個可消費 Web API 的測試工具,所以在開始測試之前,先來求問一下 Google 有沒有好用的 Web API 測試工具,看來 Postman 是不錯用的工具,就先下載來安裝使用吧:
安裝完 Postman 後,執行畫面如下圖所示,請留意圖中以橢圓圈起來的地方,這會配合接下來的程式解說時使用:
RESTful Web Service
阿源哥哥不想在此花時間解釋什麼是 RESTful Web Service 因為隨便 Google 一下就可以找到一篇比阿源哥哥寫的好的文章,但是不稍微說明一下的話,讀者可能會不太明白接下來要學習的操作內涵,所以就使用一張阿源哥哥上課時所使用的投影片來說明:
首先請回憶一下,先前說過整個應用程式的操作分為《前端》和《後端》兩部分。這時候的《前端》可以想像是我們接下來要開發的行動裝置應用程式(今天暫時用 Postman 代替),而《後端》也就是昨天我們實作出來的可對資料庫進行 CRUD 操作的 Web API 控制器動作方法(Controller Action Method)。
理解了應用程式有《前端》和《後端》之分之後,接下來的問題就是《前端》和《後端》如何溝通,也就是《前端》如何告訴《後端》想請它做什麼事,因此《前端》必需攜帶足夠的訊息到《後端》,然後《後端》才會知道《前端》要叫它做什麼事,接著執行所要求的工作,並回傳執行結果。因此前端必需至少要帶三個訊息:
- 名詞:講白一點就是他想請誰工作,而這個誰一般是使用類似網頁網址的 URL ,該被填在前面的 Postman 介面的「Enter request URL」的部分。
- 動詞:講白一點是要做什麼事,而要做的事不外乎是 GET、POST、PUT、DELETE 這些資料庫的操作,該在前面的 Postman 介面選擇。
- 格式:設定兩者資料傳遞的格式,一般內定是使用 JSON。
路由(Route)設定
剛剛在前面說過,要找到對的人請他工作,所以在控制器類別上加個 [Route("api/Addresses")]
修飾詞,將來使用 http://yourdomain/api/Addresses
即可對應到此控制器:
namespace Demae.Api.Controllers
{
[Produces("application/json")]
[Route("api/Addresses")]
public class AddressesController : Controller
{
private readonly DemaeContext _context;
public AddressesController(DemaeContext context)
{
_context = context;
}
......
......
......
}
}
而上述的 yourdomain
是什麼呢?請看下面的操作圖示,在測試階段為 localhost:18098
(註:讀者所看到的埠號可能是不同的編號,請在測試時使用自己的編號),所以在 Postman 操作介面上要填入 http://localhost:18098/api/Addresses 才可對應到(找到對的人)實作的地址相關控制器:
名詞知道了,啊!動詞呢?由如下程式碼所示,加入 [HttpGet] 修飾詞的動作方法,即可讓 Postman 下達 GET 動詞,如果沒帶 id 參數就是要執行列表(列出資料庫中所有地址),而有帶 id 參數的,就是要查詢主鍵值為所帶入 id 數值的地址:
// GET: api/Addresses
[HttpGet]
public IEnumerable<Address> GetAddresses()
{
return _context.Addresses;
}
// GET: api/Addresses/5
[HttpGet("{id}")]
public async Task<IActionResult> GetAddress([FromRoute] int id)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var address = await _context.Addresses.SingleOrDefaultAsync(m => m.Id == id);
if (address == null)
{
return NotFound();
}
return Ok(address);
}
同理,加入 [HttpPut("{id}")]
修飾詞,即可讓 Postman 下達 PUT 動詞來執行這沒修改的程式:
[HttpPut("{id}")]
public async Task<IActionResult> PutAddress([FromRoute] int id, [FromBody] Address address)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != address.Id)
{
return BadRequest();
}
_context.Entry(address).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!AddressExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
也是相同道理,加入 [HttpPost]
修飾詞,即可讓 Postman 下達 POST 動詞來執行這沒新增的程式:
[HttpPost]
public async Task<IActionResult> PostAddress([FromBody] Address address)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
_context.Addresses.Add(address);
await _context.SaveChangesAsync();
return CreatedAtAction("GetAddress", new { id = address.Id }, address);
}
最後的是,加入 [HttpDelete]
修飾詞,即可讓 Postman 下達 DELETE 動詞來執行這沒刪除的程式:
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteAddress([FromRoute] int id)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var address = await _context.Addresses.SingleOrDefaultAsync(m => m.Id == id);
if (address == null)
{
return NotFound();
}
_context.Addresses.Remove(address);
await _context.SaveChangesAsync();
return Ok(address);
}
好吧!時間不多了,今天就到些此為止,原先預定的要實際使用 Postman 進行 CRUD 的操作,以及詳細解說內部的程式碼,就留待下星期一再來努力了。