SlideShare uma empresa Scribd logo
1 de 27
BEAUTIFUL REST APIs
in ASP.NET Core
Nate Barbettini
@nbarbettini
recaffeinate.co
.ws
Overview
● Why is API design important?
● HATEOAS (Hypertext As The Engine Of Application State)
● 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
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. Fielding
Tl;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.
Good REST API design should...
● Be discoverable and self-documenting
● Represent resources and collections
● Represent actions using HTTP verbs
● KISS!
Revisiting the API example
/users GET: List all users
POST or PUT: Create a user
/users/17 GET: Retrieve a single user
POST or PUT: Update user details
DELETE: Delete this user
/users/17/posts GET: Get the user’s posts
POST: Create a post
/users?lname=Skywalker
Search
/users/17?include=posts
Include linked data
A specification for REST+JSON APIs
The ION spec: https://github.com/ionwg/ion-doc
Getting a single user
GET /users/17
{
"meta": { "href": "https://example.io/users/17" },
"firstName": "Luke",
"lastName": "Skywalker"
}
Getting a list of users
GET /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"
}]
}
Discoverable forms
GET /users
{
...
"create": {
"meta": {
"href": "https://example.io/users",
"rel": ["create-form"],
"method": "post"
},
"items": [
{ "name": "firstName" },
{ "name": "lastName" }
]
}
}
Discoverable search
GET /users
{
...
"search": {
"meta": {
"href": "https://example.io/users",
"rel": ["search-form"],
"method": "get"
},
"items": [
{ "name": "fname" },
{ "name": "lname" }
]
}
}
The starting point (API root)
GET /
{
"meta": { "href": "https://example.io/" },
"users": {
"meta": {
"href": "https://example.io/users",
"rel": ["collection"],
}
}
}
● 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
Getting a single user
GET /users/17
{
"meta": { "href": "https://example.io/users/17" },
"firstName": "Luke",
"lastName": "Skywalker"
}
public class Link
{
public string Href { get; set; }
}
public abstract class Resource
{
[JsonProperty(Order = -2)]
public Link Meta { get; set; }
}
Getting a single user
public class User : Resource
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
Getting a single user
[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
[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
Getting a list of users
GET /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"
}]
}
Getting a list of users
public class Link
{
public string Href { get; set; }
[JsonProperty(PropertyName = "rel", NullValueHandling = NullValueHandling.Ignore)]
public string[] Relations { get; set; }
}
Getting a list of users
public class Collection<T> : Resource
{
public T[] Items { get; set; }
}
Getting a list of users
public 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);
The starting point (API root)
GET /
{
"meta": { "href": "https://example.io/" },
"users": {
"meta": {
"href": "https://example.io/users",
"rel": ["collection"],
}
}
}
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);
}
}
Building and running (anywhere!)
> dotnet build
(...)
Done.
> dotnet run
(...)
Listening on https://localhost:5000
Next Steps
● Full example
https://github.com/nbarbettini/beautiful-rest-api-aspnetcore
● ION draft spec
https://github.com/ionwg/ion-doc
Thank you!
Nate Barbettini
@nbarbettini
recaffeinate.co
.ws

Mais conteúdo relacionado

Mais procurados

External Data Access with jQuery
External Data Access with jQueryExternal Data Access with jQuery
External Data Access with jQuery
Doncho Minkov
 
A Practical Guide To Hypermedia APIs - Philly.rb
A Practical Guide To Hypermedia APIs - Philly.rbA Practical Guide To Hypermedia APIs - Philly.rb
A Practical Guide To Hypermedia APIs - Philly.rb
SmartLogic
 

Mais procurados (20)

Austin Day of Rest - Introduction
Austin Day of Rest - IntroductionAustin Day of Rest - Introduction
Austin Day of Rest - Introduction
 
The never-ending REST API design debate
The never-ending REST API design debateThe never-ending REST API design debate
The never-ending REST API design debate
 
Cloud Security Monitoring and Spark Analytics
Cloud Security Monitoring and Spark AnalyticsCloud Security Monitoring and Spark Analytics
Cloud Security Monitoring and Spark Analytics
 
API Design & Security in django
API Design & Security in djangoAPI Design & Security in django
API Design & Security in django
 
Data Exploration with Elasticsearch
Data Exploration with ElasticsearchData Exploration with Elasticsearch
Data Exploration with Elasticsearch
 
RESTful Web API and MongoDB go for a pic nic
RESTful Web API and MongoDB go for a pic nicRESTful Web API and MongoDB go for a pic nic
RESTful Web API and MongoDB go for a pic nic
 
Log File Analysis: The most powerful tool in your SEO toolkit
Log File Analysis: The most powerful tool in your SEO toolkitLog File Analysis: The most powerful tool in your SEO toolkit
Log File Analysis: The most powerful tool in your SEO toolkit
 
The JSON REST API for WordPress
The JSON REST API for WordPressThe JSON REST API for WordPress
The JSON REST API for WordPress
 
Building Serverless GraphQL Backends
Building Serverless GraphQL BackendsBuilding Serverless GraphQL Backends
Building Serverless GraphQL Backends
 
The Serverless GraphQL Backend Architecture
The Serverless GraphQL Backend ArchitectureThe Serverless GraphQL Backend Architecture
The Serverless GraphQL Backend Architecture
 
Creating 3rd Generation Web APIs with Hydra
Creating 3rd Generation Web APIs with HydraCreating 3rd Generation Web APIs with Hydra
Creating 3rd Generation Web APIs with Hydra
 
OPA: The Cloud Native Policy Engine
OPA: The Cloud Native Policy EngineOPA: The Cloud Native Policy Engine
OPA: The Cloud Native Policy Engine
 
Building Next-Generation Web APIs with JSON-LD and Hydra
Building Next-Generation Web APIs with JSON-LD and HydraBuilding Next-Generation Web APIs with JSON-LD and Hydra
Building Next-Generation Web APIs with JSON-LD and Hydra
 
Building APIs in an easy way using API Platform
Building APIs in an easy way using API PlatformBuilding APIs in an easy way using API Platform
Building APIs in an easy way using API Platform
 
Design Beautiful REST + JSON APIs
Design Beautiful REST + JSON APIsDesign Beautiful REST + JSON APIs
Design Beautiful REST + JSON APIs
 
External Data Access with jQuery
External Data Access with jQueryExternal Data Access with jQuery
External Data Access with jQuery
 
A Practical Guide To Hypermedia APIs - Philly.rb
A Practical Guide To Hypermedia APIs - Philly.rbA Practical Guide To Hypermedia APIs - Philly.rb
A Practical Guide To Hypermedia APIs - Philly.rb
 
RESTful Web Services
RESTful Web ServicesRESTful Web Services
RESTful Web Services
 
Understanding REST
Understanding RESTUnderstanding REST
Understanding REST
 
GraphQL Subscriptions
GraphQL SubscriptionsGraphQL Subscriptions
GraphQL Subscriptions
 

Destaque

Destaque (7)

.NET Core in the Real World
.NET Core in the Real World.NET Core in the Real World
.NET Core in the Real World
 
Separating REST Facts from Fallacies
Separating REST Facts from FallaciesSeparating REST Facts from Fallacies
Separating REST Facts from Fallacies
 
REST: From GET to HATEOAS
REST: From GET to HATEOASREST: From GET to HATEOAS
REST: From GET to HATEOAS
 
That Conference Date and Time
That Conference Date and TimeThat Conference Date and Time
That Conference Date and Time
 
Date and Time MomentJS Edition
Date and Time MomentJS EditionDate and Time MomentJS Edition
Date and Time MomentJS Edition
 
QEMU Disk IO Which performs Better: Native or threads?
QEMU Disk IO Which performs Better: Native or threads?QEMU Disk IO Which performs Better: Native or threads?
QEMU Disk IO Which performs Better: Native or threads?
 
HATEOAS 101 - Opinionated Introduction to a REST API Style
HATEOAS 101 - Opinionated Introduction to a REST API StyleHATEOAS 101 - Opinionated Introduction to a REST API Style
HATEOAS 101 - Opinionated Introduction to a REST API Style
 

Semelhante a Building Beautiful REST APIs in ASP.NET Core

Golang slidesaudrey
Golang slidesaudreyGolang slidesaudrey
Golang slidesaudrey
Audrey Lim
 
RESTful JSON web databases
RESTful JSON web databasesRESTful JSON web databases
RESTful JSON web databases
kriszyp
 

Semelhante a Building Beautiful REST APIs in ASP.NET Core (20)

Making Java REST with JAX-RS 2.0
Making Java REST with JAX-RS 2.0Making Java REST with JAX-RS 2.0
Making Java REST with JAX-RS 2.0
 
AMS, API, RAILS and a developer, a Love Story
AMS, API, RAILS and a developer, a Love StoryAMS, API, RAILS and a developer, a Love Story
AMS, API, RAILS and a developer, a Love Story
 
Diseño y Desarrollo de APIs
Diseño y Desarrollo de APIsDiseño y Desarrollo de APIs
Diseño y Desarrollo de APIs
 
GraphQL Los Angeles Meetup Slides
GraphQL Los Angeles Meetup SlidesGraphQL Los Angeles Meetup Slides
GraphQL Los Angeles Meetup Slides
 
Tk2323 lecture 9 api json
Tk2323 lecture 9   api jsonTk2323 lecture 9   api json
Tk2323 lecture 9 api json
 
RESTful API 제대로 만들기
RESTful API 제대로 만들기RESTful API 제대로 만들기
RESTful API 제대로 만들기
 
jSession #4 - Maciej Puchalski - Zaawansowany retrofit
jSession #4 - Maciej Puchalski - Zaawansowany retrofitjSession #4 - Maciej Puchalski - Zaawansowany retrofit
jSession #4 - Maciej Puchalski - Zaawansowany retrofit
 
Golang slidesaudrey
Golang slidesaudreyGolang slidesaudrey
Golang slidesaudrey
 
Semantic Web & TYPO3
Semantic Web & TYPO3Semantic Web & TYPO3
Semantic Web & TYPO3
 
Android and REST
Android and RESTAndroid and REST
Android and REST
 
Java Libraries You Can’t Afford to Miss
Java Libraries You Can’t Afford to Miss Java Libraries You Can’t Afford to Miss
Java Libraries You Can’t Afford to Miss
 
David Gómez G. - Hypermedia APIs for headless platforms and Data Integration ...
David Gómez G. - Hypermedia APIs for headless platforms and Data Integration ...David Gómez G. - Hypermedia APIs for headless platforms and Data Integration ...
David Gómez G. - Hypermedia APIs for headless platforms and Data Integration ...
 
Cdm mil-18 - hypermedia ap is for headless platforms and data integration
Cdm mil-18 - hypermedia ap is for headless platforms and data integrationCdm mil-18 - hypermedia ap is for headless platforms and data integration
Cdm mil-18 - hypermedia ap is for headless platforms and data integration
 
Python Code Camp for Professionals 3/4
Python Code Camp for Professionals 3/4Python Code Camp for Professionals 3/4
Python Code Camp for Professionals 3/4
 
JSON and the APInauts
JSON and the APInautsJSON and the APInauts
JSON and the APInauts
 
Hypermedia APIs and HATEOAS / Wix Engineering
Hypermedia APIs and HATEOAS / Wix EngineeringHypermedia APIs and HATEOAS / Wix Engineering
Hypermedia APIs and HATEOAS / Wix Engineering
 
RESTful JSON web databases
RESTful JSON web databasesRESTful JSON web databases
RESTful JSON web databases
 
Specification-Driven Development of REST APIs by Alexander Zinchuk
Specification-Driven Development of REST APIs by Alexander Zinchuk   Specification-Driven Development of REST APIs by Alexander Zinchuk
Specification-Driven Development of REST APIs by Alexander Zinchuk
 
Example-driven Web API Specification Discovery
Example-driven Web API Specification DiscoveryExample-driven Web API Specification Discovery
Example-driven Web API Specification Discovery
 
Automatic discovery of Web API Specifications: an example-driven approach
Automatic discovery of Web API Specifications: an example-driven approachAutomatic discovery of Web API Specifications: an example-driven approach
Automatic discovery of Web API Specifications: an example-driven approach
 

Último

"Lesotho Leaps Forward: A Chronicle of Transformative Developments"
"Lesotho Leaps Forward: A Chronicle of Transformative Developments""Lesotho Leaps Forward: A Chronicle of Transformative Developments"
"Lesotho Leaps Forward: A Chronicle of Transformative Developments"
mphochane1998
 
notes on Evolution Of Analytic Scalability.ppt
notes on Evolution Of Analytic Scalability.pptnotes on Evolution Of Analytic Scalability.ppt
notes on Evolution Of Analytic Scalability.ppt
MsecMca
 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
ssuser89054b
 
DeepFakes presentation : brief idea of DeepFakes
DeepFakes presentation : brief idea of DeepFakesDeepFakes presentation : brief idea of DeepFakes
DeepFakes presentation : brief idea of DeepFakes
MayuraD1
 
Kuwait City MTP kit ((+919101817206)) Buy Abortion Pills Kuwait
Kuwait City MTP kit ((+919101817206)) Buy Abortion Pills KuwaitKuwait City MTP kit ((+919101817206)) Buy Abortion Pills Kuwait
Kuwait City MTP kit ((+919101817206)) Buy Abortion Pills Kuwait
jaanualu31
 

Último (20)

HOA1&2 - Module 3 - PREHISTORCI ARCHITECTURE OF KERALA.pptx
HOA1&2 - Module 3 - PREHISTORCI ARCHITECTURE OF KERALA.pptxHOA1&2 - Module 3 - PREHISTORCI ARCHITECTURE OF KERALA.pptx
HOA1&2 - Module 3 - PREHISTORCI ARCHITECTURE OF KERALA.pptx
 
Employee leave management system project.
Employee leave management system project.Employee leave management system project.
Employee leave management system project.
 
Engineering Drawing focus on projection of planes
Engineering Drawing focus on projection of planesEngineering Drawing focus on projection of planes
Engineering Drawing focus on projection of planes
 
Rums floating Omkareshwar FSPV IM_16112021.pdf
Rums floating Omkareshwar FSPV IM_16112021.pdfRums floating Omkareshwar FSPV IM_16112021.pdf
Rums floating Omkareshwar FSPV IM_16112021.pdf
 
"Lesotho Leaps Forward: A Chronicle of Transformative Developments"
"Lesotho Leaps Forward: A Chronicle of Transformative Developments""Lesotho Leaps Forward: A Chronicle of Transformative Developments"
"Lesotho Leaps Forward: A Chronicle of Transformative Developments"
 
Navigating Complexity: The Role of Trusted Partners and VIAS3D in Dassault Sy...
Navigating Complexity: The Role of Trusted Partners and VIAS3D in Dassault Sy...Navigating Complexity: The Role of Trusted Partners and VIAS3D in Dassault Sy...
Navigating Complexity: The Role of Trusted Partners and VIAS3D in Dassault Sy...
 
A CASE STUDY ON CERAMIC INDUSTRY OF BANGLADESH.pptx
A CASE STUDY ON CERAMIC INDUSTRY OF BANGLADESH.pptxA CASE STUDY ON CERAMIC INDUSTRY OF BANGLADESH.pptx
A CASE STUDY ON CERAMIC INDUSTRY OF BANGLADESH.pptx
 
HAND TOOLS USED AT ELECTRONICS WORK PRESENTED BY KOUSTAV SARKAR
HAND TOOLS USED AT ELECTRONICS WORK PRESENTED BY KOUSTAV SARKARHAND TOOLS USED AT ELECTRONICS WORK PRESENTED BY KOUSTAV SARKAR
HAND TOOLS USED AT ELECTRONICS WORK PRESENTED BY KOUSTAV SARKAR
 
notes on Evolution Of Analytic Scalability.ppt
notes on Evolution Of Analytic Scalability.pptnotes on Evolution Of Analytic Scalability.ppt
notes on Evolution Of Analytic Scalability.ppt
 
Thermal Engineering-R & A / C - unit - V
Thermal Engineering-R & A / C - unit - VThermal Engineering-R & A / C - unit - V
Thermal Engineering-R & A / C - unit - V
 
Bridge Jacking Design Sample Calculation.pptx
Bridge Jacking Design Sample Calculation.pptxBridge Jacking Design Sample Calculation.pptx
Bridge Jacking Design Sample Calculation.pptx
 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 
DeepFakes presentation : brief idea of DeepFakes
DeepFakes presentation : brief idea of DeepFakesDeepFakes presentation : brief idea of DeepFakes
DeepFakes presentation : brief idea of DeepFakes
 
Introduction to Serverless with AWS Lambda
Introduction to Serverless with AWS LambdaIntroduction to Serverless with AWS Lambda
Introduction to Serverless with AWS Lambda
 
Online food ordering system project report.pdf
Online food ordering system project report.pdfOnline food ordering system project report.pdf
Online food ordering system project report.pdf
 
AIRCANVAS[1].pdf mini project for btech students
AIRCANVAS[1].pdf mini project for btech studentsAIRCANVAS[1].pdf mini project for btech students
AIRCANVAS[1].pdf mini project for btech students
 
S1S2 B.Arch MGU - HOA1&2 Module 3 -Temple Architecture of Kerala.pptx
S1S2 B.Arch MGU - HOA1&2 Module 3 -Temple Architecture of Kerala.pptxS1S2 B.Arch MGU - HOA1&2 Module 3 -Temple Architecture of Kerala.pptx
S1S2 B.Arch MGU - HOA1&2 Module 3 -Temple Architecture of Kerala.pptx
 
data_management_and _data_science_cheat_sheet.pdf
data_management_and _data_science_cheat_sheet.pdfdata_management_and _data_science_cheat_sheet.pdf
data_management_and _data_science_cheat_sheet.pdf
 
Kuwait City MTP kit ((+919101817206)) Buy Abortion Pills Kuwait
Kuwait City MTP kit ((+919101817206)) Buy Abortion Pills KuwaitKuwait City MTP kit ((+919101817206)) Buy Abortion Pills Kuwait
Kuwait City MTP kit ((+919101817206)) Buy Abortion Pills Kuwait
 
Online electricity billing project report..pdf
Online electricity billing project report..pdfOnline electricity billing project report..pdf
Online electricity billing project report..pdf
 

Building Beautiful REST APIs in ASP.NET Core

  • 1. BEAUTIFUL REST APIs in ASP.NET Core Nate Barbettini @nbarbettini recaffeinate.co .ws
  • 2. Overview ● Why is API design important? ● HATEOAS (Hypertext As The Engine Of Application State) ● REST APIs in ASP.NET Core
  • 3. /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
  • 4. 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. Fielding Tl;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.
  • 5. Good REST API design should... ● Be discoverable and self-documenting ● Represent resources and collections ● Represent actions using HTTP verbs ● KISS!
  • 6. Revisiting the API example /users GET: List all users POST or PUT: Create a user /users/17 GET: Retrieve a single user POST or PUT: Update user details DELETE: Delete this user /users/17/posts GET: Get the user’s posts POST: Create a post /users?lname=Skywalker Search /users/17?include=posts Include linked data
  • 7. A specification for REST+JSON APIs The ION spec: https://github.com/ionwg/ion-doc
  • 8. Getting a single user GET /users/17 { "meta": { "href": "https://example.io/users/17" }, "firstName": "Luke", "lastName": "Skywalker" }
  • 9. Getting a list of users GET /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" }] }
  • 10. Discoverable forms GET /users { ... "create": { "meta": { "href": "https://example.io/users", "rel": ["create-form"], "method": "post" }, "items": [ { "name": "firstName" }, { "name": "lastName" } ] } }
  • 11. Discoverable search GET /users { ... "search": { "meta": { "href": "https://example.io/users", "rel": ["search-form"], "method": "get" }, "items": [ { "name": "fname" }, { "name": "lname" } ] } }
  • 12. The starting point (API root) GET / { "meta": { "href": "https://example.io/" }, "users": { "meta": { "href": "https://example.io/users", "rel": ["collection"], } } }
  • 13. ● 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
  • 14. Getting a single user GET /users/17 { "meta": { "href": "https://example.io/users/17" }, "firstName": "Luke", "lastName": "Skywalker" }
  • 15. public class Link { public string Href { get; set; } } public abstract class Resource { [JsonProperty(Order = -2)] public Link Meta { get; set; } } Getting a single user
  • 16. public class User : Resource { public string FirstName { get; set; } public string LastName { get; set; } } Getting a single user
  • 17. [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
  • 18. [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
  • 19. Getting a list of users GET /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" }] }
  • 20. Getting a list of users public class Link { public string Href { get; set; } [JsonProperty(PropertyName = "rel", NullValueHandling = NullValueHandling.Ignore)] public string[] Relations { get; set; } }
  • 21. Getting a list of users public class Collection<T> : Resource { public T[] Items { get; set; } }
  • 22. Getting a list of users public 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);
  • 23. The starting point (API root) GET / { "meta": { "href": "https://example.io/" }, "users": { "meta": { "href": "https://example.io/users", "rel": ["collection"], } } }
  • 24. 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); } }
  • 25. Building and running (anywhere!) > dotnet build (...) Done. > dotnet run (...) Listening on https://localhost:5000
  • 26. Next Steps ● Full example https://github.com/nbarbettini/beautiful-rest-api-aspnetcore ● ION draft spec https://github.com/ionwg/ion-doc

Notas do Editor

  1. I work as a .NET developer evangelist at Stormpath in San Francisco. We help developers build more secure applications and make things like social login, SSO, multitenancy, and authorization easy. Since our core product is an API that other people have to use, we’ve studied API design a lot and naturally have some opinions.
  2. Starts out innocent enough. Just need to add a few routes for functionality. 2 2 Get all accounts, search for an account. 1 Get posts for a specific user 1 Include for efficiency 1 Now we need JSON, 1 everywhere 1 Except for search, which already returned JSON. XML to make it consistent 1 Jimmy, 1 Jimmy, 1 Jimmy Not REST! This is like half-baked RPC and SOAP all over again. Bad design has a way of getting worse, not better. What’s wrong with these routes? (Verbs, return type, discoverability, how many return values)
  3. Can a junior developer understand it without documentation? Can a machine? Think of how a web browser retrieves and parses pages. It doesn’t need any documentation beforehand.
  4. This single endpoint captures all of the functionality from before! Designing RESTful endpoints is one half. It isn’t HATEOAS until we define some good responses too.