SlideShare una empresa de Scribd logo
1 de 27
Descargar para leer sin conexión
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

Más contenido relacionado

La actualidad más candente

External Data Access with jQuery
External Data Access with jQueryExternal Data Access with jQuery
External Data Access with jQuery
Doncho Minkov
 
Rest presentation
Rest  presentationRest  presentation
Rest presentation
srividhyau
 

La actualidad más candente (19)

Best Practices for Architecting a Pragmatic Web API.
Best Practices for Architecting a Pragmatic Web API.Best Practices for Architecting a Pragmatic Web API.
Best Practices for Architecting a Pragmatic Web API.
 
Designing a beautiful REST json api
Designing a beautiful REST json apiDesigning a beautiful REST json api
Designing a beautiful REST json api
 
External Data Access with jQuery
External Data Access with jQueryExternal Data Access with jQuery
External Data Access with jQuery
 
Understanding REST
Understanding RESTUnderstanding REST
Understanding REST
 
Best practices for RESTful web service design
Best practices for RESTful web service designBest practices for RESTful web service design
Best practices for RESTful web service design
 
RESTful API Design Best Practices Using ASP.NET Web API
RESTful API Design Best Practices Using ASP.NET Web APIRESTful API Design Best Practices Using ASP.NET Web API
RESTful API Design Best Practices Using ASP.NET Web API
 
The never-ending REST API design debate -- Devoxx France 2016
The never-ending REST API design debate -- Devoxx France 2016The never-ending REST API design debate -- Devoxx France 2016
The never-ending REST API design debate -- Devoxx France 2016
 
GraphQL & Relay - 串起前後端世界的橋樑
GraphQL & Relay - 串起前後端世界的橋樑GraphQL & Relay - 串起前後端世界的橋樑
GraphQL & Relay - 串起前後端世界的橋樑
 
RESTful Web Services
RESTful Web ServicesRESTful Web Services
RESTful Web Services
 
Rest API
Rest APIRest API
Rest API
 
Austin Day of Rest - Introduction
Austin Day of Rest - IntroductionAustin Day of Rest - Introduction
Austin Day of Rest - Introduction
 
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
 
Rest presentation
Rest  presentationRest  presentation
Rest presentation
 
Representational State Transfer (REST) and HATEOAS
Representational State Transfer (REST) and HATEOASRepresentational State Transfer (REST) and HATEOAS
Representational State Transfer (REST) and HATEOAS
 
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
 
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
 
Understanding REST APIs in 5 Simple Steps
Understanding REST APIs in 5 Simple StepsUnderstanding REST APIs in 5 Simple Steps
Understanding REST APIs in 5 Simple Steps
 
Data Exploration with Elasticsearch
Data Exploration with ElasticsearchData Exploration with Elasticsearch
Data Exploration with Elasticsearch
 

Destacado

Destacado (20)

Stormpath 101: Spring Boot + Spring Security
Stormpath 101: Spring Boot + Spring SecurityStormpath 101: Spring Boot + Spring Security
Stormpath 101: Spring Boot + Spring Security
 
Secure API Services in Node with Basic Auth and OAuth2
Secure API Services in Node with Basic Auth and OAuth2Secure API Services in Node with Basic Auth and OAuth2
Secure API Services in Node with Basic Auth and OAuth2
 
Storing User Files with Express, Stormpath, and Amazon S3
Storing User Files with Express, Stormpath, and Amazon S3Storing User Files with Express, Stormpath, and Amazon S3
Storing User Files with Express, Stormpath, and Amazon S3
 
JWTs for CSRF and Microservices
JWTs for CSRF and MicroservicesJWTs for CSRF and Microservices
JWTs for CSRF and Microservices
 
Mobile Authentication for iOS Applications - Stormpath 101
Mobile Authentication for iOS Applications - Stormpath 101Mobile Authentication for iOS Applications - Stormpath 101
Mobile Authentication for iOS Applications - Stormpath 101
 
Token Authentication in ASP.NET Core
Token Authentication in ASP.NET CoreToken Authentication in ASP.NET Core
Token Authentication in ASP.NET Core
 
Custom Data Search with Stormpath
Custom Data Search with StormpathCustom Data Search with Stormpath
Custom Data Search with Stormpath
 
Spring Boot Authentication...and More!
Spring Boot Authentication...and More! Spring Boot Authentication...and More!
Spring Boot Authentication...and More!
 
JWTs in Java for CSRF and Microservices
JWTs in Java for CSRF and MicroservicesJWTs in Java for CSRF and Microservices
JWTs in Java for CSRF and Microservices
 
Instant Security & Scalable User Management with Spring Boot
Instant Security & Scalable User Management with Spring BootInstant Security & Scalable User Management with Spring Boot
Instant Security & Scalable User Management with Spring Boot
 
Multi-Tenancy with Spring Boot
Multi-Tenancy with Spring Boot Multi-Tenancy with Spring Boot
Multi-Tenancy with Spring Boot
 
The Ultimate Guide to Mobile API Security
The Ultimate Guide to Mobile API SecurityThe Ultimate Guide to Mobile API Security
The Ultimate Guide to Mobile API Security
 
Browser Security 101
Browser Security 101 Browser Security 101
Browser Security 101
 
REST API Security: OAuth 2.0, JWTs, and More!
REST API Security: OAuth 2.0, JWTs, and More!REST API Security: OAuth 2.0, JWTs, and More!
REST API Security: OAuth 2.0, JWTs, and More!
 
Building Secure User Interfaces With JWTs (JSON Web Tokens)
Building Secure User Interfaces With JWTs (JSON Web Tokens)Building Secure User Interfaces With JWTs (JSON Web Tokens)
Building Secure User Interfaces With JWTs (JSON Web Tokens)
 
Getting Started With Angular
Getting Started With AngularGetting Started With Angular
Getting Started With Angular
 
Securing Web Applications with Token Authentication
Securing Web Applications with Token AuthenticationSecuring Web Applications with Token Authentication
Securing Web Applications with Token Authentication
 
Build a REST API for your Mobile Apps using Node.js
Build a REST API for your Mobile Apps using Node.jsBuild a REST API for your Mobile Apps using Node.js
Build a REST API for your Mobile Apps using Node.js
 
Token Authentication for Java Applications
Token Authentication for Java ApplicationsToken Authentication for Java Applications
Token Authentication for Java Applications
 
So long scrum, hello kanban
So long scrum, hello kanbanSo long scrum, hello kanban
So long scrum, hello kanban
 

Similar 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
 

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

The JSON REST API for WordPress
The JSON REST API for WordPressThe JSON REST API for WordPress
The JSON REST API for WordPress
 
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
 

Más de Stormpath

Más de Stormpath (7)

How to Use Stormpath in angular js
How to Use Stormpath in angular jsHow to Use Stormpath in angular js
How to Use Stormpath in angular js
 
Rest API Security
Rest API SecurityRest API Security
Rest API Security
 
Elegant Rest Design Webinar
Elegant Rest Design WebinarElegant Rest Design Webinar
Elegant Rest Design Webinar
 
Secure Your REST API (The Right Way)
Secure Your REST API (The Right Way)Secure Your REST API (The Right Way)
Secure Your REST API (The Right Way)
 
Build a Node.js Client for Your REST+JSON API
Build a Node.js Client for Your REST+JSON APIBuild a Node.js Client for Your REST+JSON API
Build a Node.js Client for Your REST+JSON API
 
Build A Killer Client For Your REST+JSON API
Build A Killer Client For Your REST+JSON APIBuild A Killer Client For Your REST+JSON API
Build A Killer Client For Your REST+JSON API
 
REST API Design for JAX-RS And Jersey
REST API Design for JAX-RS And JerseyREST API Design for JAX-RS And Jersey
REST API Design for JAX-RS And Jersey
 

Último

+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Victor Rentea
 

Último (20)

+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
Platformless Horizons for Digital Adaptability
Platformless Horizons for Digital AdaptabilityPlatformless Horizons for Digital Adaptability
Platformless Horizons for Digital Adaptability
 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
 
Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
 
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
 
CNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In PakistanCNIC Information System with Pakdata Cf In Pakistan
CNIC Information System with Pakdata Cf In Pakistan
 
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot ModelMcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
 
Vector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptxVector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptx
 
WSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering DevelopersWSO2's API Vision: Unifying Control, Empowering Developers
WSO2's API Vision: Unifying Control, Empowering Developers
 

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