27
BEAUTIFUL REST APIs in ASP.NET Core Nate Barbettini @nbarbettini recaffeinate.co .ws

Building Beautiful REST APIs in ASP.NET Core

Embed Size (px)

Citation preview

Page 1: Building Beautiful REST APIs in ASP.NET Core

BEAUTIFUL REST APIsin ASP.NET Core

Nate Barbettini@nbarbettini

recaffeinate.co .ws

Page 2: Building Beautiful REST APIs in ASP.NET Core

Overview● Why is API design important?● HATEOAS (Hypertext As The Engine Of Application

State)● REST APIs in ASP.NET Core

Page 3: Building Beautiful REST APIs in ASP.NET Core

/getAccount?id=17

Bad REST API design

/getAccount?all=1&includePosts=1

/getAllAccounts

/updateAccount?id=17

/createAccount

/findPostsByAccountId?account=17

/accountSearch?lname=Skywalker

/getAccount?id=17&includePosts=1

/getAccount?id=17&format=json

/getAllAccountsJson

/updateAccount?id=17&return=json

/createAccountJson

/accountSearch?lname=Skywalker&xml=1

/findPostsByAccountIdJSON?account=17

/getAllPosts?filter=account&id=17

/countAccounts

/partialUpdateAccount?id=17

/getPostCount?id=17

/deleteUser

Page 4: Building Beautiful REST APIs in ASP.NET Core

HATEOAS, yo!"A REST API should be entered with no prior knowledge beyond the initial URI (bookmark) and set of standardized media types that are appropriate for the intended audience (i.e., expected to be understood by any client that might use the API). From that point on, all application state transitions must be driven by client selection of server-provided choices that are present in the received representations or implied by the user’s manipulation of those representations." ~ Dr. FieldingTl;dr The API responses

themselves should document what you are allowed to do and where you can go.

If you can get to the root (/), you should be able to “travel” anywhere else in the API.

Page 5: Building Beautiful REST APIs in ASP.NET Core

Good REST API design should...●Be discoverable and self-documenting

●Represent resources and collections

●Represent actions using HTTP verbs

●KISS!

Page 6: Building Beautiful REST APIs in ASP.NET Core

Revisiting the API example/users GET: List all users

POST or PUT: Create a user

/users/17 GET: Retrieve a single userPOST or PUT: Update user detailsDELETE: Delete this user

/users/17/posts GET: Get the user’s postsPOST: Create a post

/users?lname=SkywalkerSearch

/users/17?include=postsInclude linked data

Page 7: Building Beautiful REST APIs in ASP.NET Core

A specification for REST+JSON APIsThe ION spec: https://github.com/ionwg/ion-doc

Page 8: Building Beautiful REST APIs in ASP.NET Core

Getting a single userGET /users/17

{ "meta": { "href": "https://example.io/users/17" }, "firstName": "Luke", "lastName": "Skywalker"}

Page 9: Building Beautiful REST APIs in ASP.NET Core

Getting a list of usersGET /users

{ "meta": { "href": "https://example.io/users", "rel": ["collection"] }, "items": [{

"meta": { "href": "https://example.io/users/17" }, "firstName": "Luke", "lastName": "Skywalker"}, { "meta": { "href": "https://example.io/users/18" }, "firstName": "Han", "lastName": "Solo"}]}

Page 10: Building Beautiful REST APIs in ASP.NET Core

Discoverable formsGET /users

{ ...

"create": { "meta": { "href": "https://example.io/users", "rel": ["create-form"], "method": "post" }, "items": [ { "name": "firstName" }, { "name": "lastName" } ] }}

Page 11: Building Beautiful REST APIs in ASP.NET Core

Discoverable searchGET /users

{ ...

"search": { "meta": { "href": "https://example.io/users", "rel": ["search-form"], "method": "get" }, "items": [ { "name": "fname" }, { "name": "lname" } ] }}

Page 12: Building Beautiful REST APIs in ASP.NET Core

The starting point (API root)GET /

{ "meta": { "href": "https://example.io/" }, "users": { "meta": { "href": "https://example.io/users", "rel": ["collection"], } }}

Page 13: Building Beautiful REST APIs in ASP.NET Core

● Install the .NET Core SDK - http://dot.net/core● If you’re using Visual Studio:

○ Install the latest updates (Update 3)○ Install the .NET Core tooling -

https://go.microsoft.com/fwlink/?LinkID=824849● Or, install Visual Studio Code● Create a new project from the ASP.NET Core (.NET Core) template● Pick the API subtemplate● Ready to run!

Getting started with ASP.NET Core

Page 14: Building Beautiful REST APIs in ASP.NET Core

Getting a single userGET /users/17

{ "meta": { "href": "https://example.io/users/17" }, "firstName": "Luke", "lastName": "Skywalker"}

Page 15: Building Beautiful REST APIs in ASP.NET Core

public class Link{ public string Href { get; set; }}

public abstract class Resource{ [JsonProperty(Order = -2)] public Link Meta { get; set; }}

Getting a single user

Page 16: Building Beautiful REST APIs in ASP.NET Core

public class User : Resource{ public string FirstName { get; set; }

public string LastName { get; set; }}

Getting a single user

Page 17: Building Beautiful REST APIs in ASP.NET Core

[Route("/users")]public class UsersController : Controller{ private readonly BulletinBoardDbContext _context; private readonly IUrlHelperFactory _urlHelperFactory;

public UsersController( BulletinBoardDbContext context, IUrlHelperFactory urlHelperFactory) { _context = context; _urlHelperFactory = urlHelperFactory; }

Getting a single user

Page 18: Building Beautiful REST APIs in ASP.NET Core

[Route("{id}")]public async Task<IActionResult> GetUser(string id){ var user = await _context.Users.SingleOrDefaultAsync(x => x.Id == id); if (user == null) return NotFound();

var urlHelper = _urlHelperFactory.GetUrlHelper(ControllerContext); var url = urlHelper.Link("default", new { controller = "users", id = user.Id });

var response = new User() { Meta = new Link() { Href = url }, FirstName = user.FirstName, LastName = user.LastName };

return Ok(response);}

Getting a single user

Page 19: Building Beautiful REST APIs in ASP.NET Core

Getting a list of usersGET /users

{ "meta": { "href": "https://example.io/users", "rel": ["collection"] }, "items": [{

"meta": { "href": "https://example.io/users/17" }, "firstName": "Luke", "lastName": "Skywalker"}, { "meta": { "href": "https://example.io/users/18" }, "firstName": "Han", "lastName": "Solo"}]}

Page 20: Building Beautiful REST APIs in ASP.NET Core

Getting a list of userspublic class Link{ public string Href { get; set; }

[JsonProperty(PropertyName = "rel", NullValueHandling = NullValueHandling.Ignore)] public string[] Relations { get; set; }}

Page 21: Building Beautiful REST APIs in ASP.NET Core

Getting a list of userspublic class Collection<T> : Resource{ public T[] Items { get; set; }}

Page 22: Building Beautiful REST APIs in ASP.NET Core

Getting a list of userspublic async Task<IActionResult> GetAll(){ var urlHelper = _urlHelperFactory.GetUrlHelper(ControllerContext); var allUsers = await _context.Users.ToArrayAsync();

var projected = allUsers.Select(x => new User() { Meta = new Link() { Href = urlHelper.Link("default", new { controller = "users", id = x.Id }) }, FirstName = x.FirstName, LastName = x.LastName });

var response = new Collection<User>() { Meta = new Link() { Href = urlHelper.Link("default", new { controller = "users" }), Relations = new string[] {"collection"}, }, Items = projected.ToArray() }; return Ok(response);}

Page 23: Building Beautiful REST APIs in ASP.NET Core

The starting point (API root)GET /

{ "meta": { "href": "https://example.io/" }, "users": { "meta": { "href": "https://example.io/users", "rel": ["collection"], } }}

Page 24: Building Beautiful REST APIs in ASP.NET Core

Adding a root route[Route("/")]public class RootController : Controller{ private readonly IUrlHelperFactory _urlHelperFactory; public RootController(IUrlHelperFactory urlHelperFactory) { _urlHelperFactory = urlHelperFactory; }

public IActionResult Get() { var urlHelper = _urlHelperFactory.GetUrlHelper(ControllerContext); var response = new { meta = new Link() { Href = urlHelper.Link("default", new { controller = "root" }) }, users = new Link() { Href = urlHelper.Link("default", new { controller = "users" }), Relations = new string[] {"collection"} } }; return Ok(response); }}

Page 25: Building Beautiful REST APIs in ASP.NET Core

Building and running (anywhere!)> dotnet build(...)Done.

> dotnet run(...)Listening on https://localhost:5000

Page 26: Building Beautiful REST APIs in ASP.NET Core

Next Steps● Full example

https://github.com/nbarbettini/beautiful-rest-api-aspnetcore

● ION draft spechttps://github.com/ionwg/ion-doc

Page 27: Building Beautiful REST APIs in ASP.NET Core

Thank you!Nate Barbettini

@nbarbettinirecaffeinate.co .ws