Upload
others
View
1
Download
0
Embed Size (px)
Citation preview
About me• Microsoft MVP
• Asp.NET Insider
• Web API Advisor
• Pluralsight contributor
• Dev Chair – DevConnections
• Conference Organizer – MVPMIX.com
• Conference Organizer - jsSaturday
• Leader – Rockstar Developers Meetup Austin
• Leader – .NET user group at UTDallas
• President– Chander Dhall, Inc.
Agenda• REST Principles
• Web API – Best Practices
• A Typical Web API Pipeline
3
• Participation == :-)
• No participation == :-(
ChanderDhall.com/Podcasts
Free Resharper
• http://ChanderDhall.com/CodeCamp
Step 1
Appserver & DBServer
Database ServerApp Server
Awesome Solution?
Load BalancerLoad
Balancer
DB
DB
DB
DB Cluster
Has
h Ma
p
DB
DB
DB
DB Cluster
Load BalancerLoad
Balancer
DB
DB
DB
DB Cluster
Has
h Ma
p
DB
DB
DB
DB Cluster
Set 1-10 Million Users Set 11-20 Million Users
Global Redirector
Global
Look up Hash
Map
May be close to an awesome
solution?Load Balancer
Load
Balancer
DB
DB
DB
DB Cluster
Hash
Map
DB
DB
DB
DB Cluster
Master
Slave Slave
SANNo Sql
Master
Slave Slave
Search Db
CachingOffline
Processing
Why?
• Amazon claim – Just an extra 1/10th of a second
on their response times will cost them 1% in sales.
• Google – ½ a second increase in latency caused
traffic to drop by a fifth.
1. REST Principles
Principle 1 - Client-server● Clients are not concerned with data storage,
which remains internal to each server.
● Servers are not concerned with the user
interface or user state.
● Servers and clients may also be replaced
and developed independently, as long as
the interface between them is not altered.
1. REST Principles
Principle 2 - Stateless● The client–server communication is further
constrained by no client context being
stored on the server between requests.
No sql paradigm – Materialized
pathsElectronics
TV Phones Computers Cameras
Samsung Apple LG
LCD LED
No sql paradigm – Materialized
pathsTV
Samsung Apple LG
LCD LED
{ “entity”: “TV”,
“category”:”Electronics”}{ “entity”: “Samsung”, “category”:”Electronics, TV”}
{ “entity”: “Samsung”, “category”:”Electronics, TV, LCD”}
1. REST Principles
Principle 3 - Cacheable● Clients can cache responses.● Responses must therefore, implicitly or
explicitly, define themselves as cacheable, or not, to prevent clients reusing stale or inappropriate data in response to further requests.
● Well-managed caching partially or completely eliminates some client–server interactions, further improving scalability and performance.
1. REST Principles
Principle 4 - Layered system● A client cannot ordinarily tell whether it is
connected directly to the end server, or to
an intermediary along the way.
● Intermediary servers may improve system
scalability by enabling load-balancing and
by providing shared caches.
No sql paradigm – Nested sets
Electronics
TV Phones
Samsung Sony Cell Landline1 2 3 4 5 6 7 8 9 10 11 12 13 14
1. REST Principles
Principle 5 - Code on demand● Servers are able temporarily to extend or
customize the functionality of a client by
the transfer of executable code.
1. REST Principles
Principle 6 - Uniform Interface● The uniform interface between clients and
servers, discussed below, simplifies and
decouples the architecture, which enables
each part to evolve independently.
http://ChanderDhall.com/gettrainings
GET
http://ChanderDhall.com/trainings
Principle: Use HTTP verbs
20
Nouns, No Verbs in the URL
What about?
• Responses that don’t involve resources
• Use verbs
• Example:
http://ChanderDhall.com/translate?from=en
&to=gn
http://ChanderDhall.com/trainings
http://ChanderDhall.com/trainings/34
Principle: 2 base
URLs/resource
22
KISS (Keep it simple, stupid!)
• HTTP Verbs
GET
http://ChanderDhall.com/trainings
Retrieves all trainings
GET
http://ChanderDhall.com/trainings/23
Retrieves trainings with Id = 2323
GET
• HTTP Verbs
POST
http://ChanderDhall.com/trainings
Creates a new training(Strange?)
POST
http://ChanderDhall.com/trainings/23
Error – Why, so?
24
POST
• HTTP Verbs
PUT
http://ChanderDhall.com/trainings
Bulk update trainings
PUT
http://ChanderDhall.com/trainings/23
If exists, update 23
Else ERROR
25
PUT
• HTTP Verbs
DELETE
http://ChanderDhall.com/trainings
Delete all trainings
DELETE
http://ChanderDhall.com/trainings/23
If exists, Delete 23
Else Resource Not found Error
26
DELETE
Associations
GET
/trainers/12/trainings/144
27
GET
/trainers/12/trainings?zip=926
18&tech=api
28
Complexity
Error Format
• Error format 1
{
“code" : "401",
"message“ : "Authenticate",
}
29
Error Format
• Error format 2
{
“type" : “OAuthException",
"message“ : “(#401: Request not authorized",
}
30
Error Format
• Error format 3
{
"status" : "401",
"message“ : "Authenticate",
"code“ : 1234,
“details":
"http://www.chanderdhall.com/docs/errors/1234"
}
31
(Recommended!)
Error Format
• Google GData 200 201 304 400 401 403
404 409 410 500
• Netflix 200 201 304 400 401 403 404 412
500
• Digg 200 400 401 403 404 410 500 503
Errors
• Only 3 cases
• Everything worked
• Client did something wrong
• API did something wrong
33
Error Codes (Required)
• So minimum response codes
• 200 - OK
• 400 - Bad Request
• 500 - Internal Server Error
34
Error Codes (Extended)
• 201 - Created
• 304 - Not Modified
• 404 – Not Found
• 401 - Unauthorized
• 403 - Forbidden
35
Versioning
• /bankName/v2.0/accounts/checking
• /2013-09-10/bankName/accounts/checkingThis
• /bankName/accounts/checking?v=1
36
Versioning
• Timestamp: Is the version based on the
date of launch or date of creation?
• Version in URL: Interface appears to
change sooner that it actually might.
• Version is optional: (Red Flag)
37
Versioning
• Versioning is mandatory
• Make version the first field if you want
from the left (v1/trainings)
• How many versions to maintain?
• URLs or Headers?
38
Versioning
• Accept-Datetime: Thu, 1 Oct 2013
20:35:00 GMT
• Cookie: $Version=1; Skin=new;
• ETag:
"737060cd8c284d8af7ad3082f209582d"
39
Pagination
• http://chanderdhall.com/podcasts?page
=3&rpp=5
• http://chanderdhall.com/podcasts?start=
3&count=5
40
Pagination
• http://chanderdhall.com/podcasts?offset
=3&limit=5
• Don’t forget to include Default Pagination
41
Multiple Formats
• http://chanderdhall.com/podcasts?type=json
Or
http://chanderdhall.com/podcasts?type=xml
• http://chanderdhall.com/podcasts.json
Or http://chanderdhall.com/podcasts.xml
42
Multiple Formats
• http://chanderdhall.com/podcasts
accept: application/json
43
Responses
a. "Created_At": "2013-10-10T04:35:00Z"
b. "DateTime": "2013-10-10T04:35:00Z"
44
Responses
var podcast = JSON.parse(response);
podcast.createdAt
45
P
I
P
E
L
I
N
E
W
E
B
A
P
I
ASP.NET Hosting Self Hosting
HttpControllerHandler
HttpServer HttpSelfHostServer
DelegatingHandler
HttpRoutingDispatcher
HttpControllerDispatcher
HttpRequestMessage HttpResponse
Message
If(Route.Handler) Yes Route.Handler
DelegatingHandler
HttpMessageHandler
No
1. Create API Controller
Message Handlers
W
E
B
A
P
I
Action Filters
2. Select Controller ActionP
I
P
E
L
I
N
E
Controller
Can create an error response if request is not
authorized3. Model Binding
Authorization Filters
Action filters are invoked
twice
4. Result Conversion
5. Invoke Action
OnActionExecuting OnActionExecuted
Controller Action
Exception Filters
3. Model Binding
HttpRequestMessage
URI Headers Body
IModelBinder
ModelBinderParameterBinding
IValueProvider
Simple Type Any Type
HttpParameterBinding
Complex Type
MediaTypeFormatter
FormatterParameterBinding
4. Result Conversion
HttpResponseMessage
void
If(returnType== void)
return (204)
HttpResponseMessage
If(returnType == HttpResponseMessage)
Pass through
Other Types
IContentNegotiator
MediaTypeFormatter
Features you should know about
• Documentation
Features you should know about
• Test Client (Nuget)
• Install-Package WebApiTestClient
Features you should know about
• External Authentication Services
● Microsoft Accounts.
• And more
Features you should know about
• Unit Testing
Features you should know about
• Enable Cross Origin Requests
Install-Package
Microsoft.AspNet.WebApi.Cors -pre -
project WebService
Enable Cross Origin Requests
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
var cors = new
EnableCorsAttribute("www.example.com", "*", “*");
config.EnableCors(cors);
// ...
}
}
Behind the scenes
Access-Control-Allow-Origin: http://www.example.com
Access-Control-Allow-Headers: x-my-custom-header
Access-Control-Allow-Methods: PUT
Enable CORS (Method Level)
public class ItemsController : ApiController
{
public HttpResponseMessage GetAll() { ... }
[EnableCors(origins: "http://www.example.com",
headers: "*", methods: "*")]
public HttpResponseMessage GetItem(int id) { ... }
public HttpResponseMessage Post() { ... }
public HttpResponseMessage PutItem(int id) { ... }
}
Enable CORS (Controller level)
[EnableCors(origins: "http://www.example.com", headers:
"*", methods: "*")]
public class ItemsController : ApiController
{
public HttpResponseMessage GetAll() { ... }
public HttpResponseMessage GetItem(int id) { ... }
public HttpResponseMessage Post() { ... }
[DisableCors]
public HttpResponseMessage PutItem(int id) { ... }
}
Enable CORS (Custom)public class MyCorsPolicyAttribute : Attribute, ICorsPolicyProvider{
private CorsPolicy _policy;
public MyCorsPolicyAttribute(){
// Create a CORS policy._policy = new CorsPolicy{
AllowAnyMethod = true,AllowAnyHeader = true
};
// Add allowed origins._policy.Origins.Add("http://myclient.azurewebsites.net");_policy.Origins.Add("http://www.contoso.com");
}
public Task<CorsPolicy> GetCorsPolicyAsync(HttpRequestMessage request)
{return Task.FromResult(_policy);
}}
Web API 2 (New Features)
• Attribute Routing
Attribute Routing
[Route("api/books")]
public IEnumerable<Book> GetBooks() { ... }
[Route("api/books/{id:int}")]
public Book GetBook(int id) { ... }
[Route("api/books")]
public HttpResponseMessage CreateBook(Book
book) { ... }
Attribute Routing
[RoutePrefix("api/books")]
public class BooksController : ApiController
{
// GET api/books
[Route("")]
public IEnumerable<Book> Get() { ... }
// GET api/books/5
[Route("{id:int}")]
public Book Get(int id) { ... }
// POST api/books
[Route("")]
public HttpResponseMessage Post(Book book) { ... }
}
Attribute Routing
[RoutePrefix("api/books")]
public class BooksController : ApiController
{
// GET /api/authors/1/books
[Route("~/api/authors/{authorId:int}/books")]
public IEnumerable<Book> GetByAuthor(int authorId) {
... }
// ...
}
‘~’ Overrides the RoutePrefix
Attribute Routing
[RoutePrefix("customers/{customerId}")]
public class OrdersController : ApiController
{
// GET customers/1/orders
[Route("orders")]
public IEnumerable<Order> Get(int customerId) { ... }
}
Attribute Routing
[Route("users/{id:int}"]
public User GetUserById(int id) { ... }
[Route("users/{name}"]
public User GetUserByName(string name) { ... }
First route chosen if the id is an int.
Otherwise, second.
Constraint Description Example
alphaMatches uppercase or lowercase Latin
alphabet characters (a-z, A-Z){x:alpha}
bool Matches a Boolean value. {x:bool}
datetime Matches a DateTime value. {x:datetime}
decimal Matches a decimal value. {x:decimal}
double Matches a 64-bit floating-point value. {x:double}
float Matches a 32-bit floating-point value. {x:float}
guid Matches a GUID value. {x:guid}
int Matches a 32-bit integer value. {x:int}
lengthMatches a string with the specified length or
within a specified range of lengths.
{x:length(6)}
{x:length(1,20)}
long Matches a 64-bit integer value. {x:long}
max Matches an integer with a maximum value. {x:max(10)}
maxlength Matches a string with a maximum length. {x:maxlength(10)}
min Matches an integer with a minimum value. {x:min(10)}
minlength Matches a string with a minimum length. {x:minlength(10)}
range Matches an integer within a range of values. {x:range(10,50)}
regex Matches a regular expression. {x:(^\d{3}-\d{3}-\d{4}$)}
Attribute Routing
[Route("users/{id:int:min(1), id:int:max(10)}")]
public User GetUserById(int id) { ... }
Multiple constraints can be applied separated by a
comma
No sql paradigm – Index table
Employee Id Details
1234 Email: [email protected]; State: CA; Dept: IT
8235 Email: [email protected]; State: TX; Dept: Sales
2234 Email: [email protected]; State: AL; Dept: IT
1671 Email: [email protected]; State: WA; Dept: Sales
State Employee Id
CA 1234, 1235, 1236, 1244
TX 8000, 8100, 8235, 8266
AL 2212, 2221, 2234, 2256
Dept Employee Id
IT 1234, 1235, 1236, 1244
Sales 8000, 8100, 8235, 8266
Acc 2212, 2221, 2234, 2256
No sql paradigm – Tree Index
Country - USA
State - CA
City - LA
Properties
Facilities
{
“property”:
[{ “facilityName”:
“abc”,
“facilityId”:”111”},
{“facilityName”:”
xyz” ,
“facilityId”:”222”}]
}
No sql paradigm – Composite Key
Dept= IT:* or
Dept= Sales:Online:*
IT: Software: 1123 EmpName: John; Address: Los Angeles
IT: Software: 2323 EmpName: Kevin; Address: Dallas, TX
IT: Hardware: 6767 EmpName: Matt; Address: San Francisco
Sales: Online: 832 EmpName: Katie: Address: Austin, Tx
Sales : Online: 423 EmpName: Karen: Address: Irvine, CA
Sales : Store : 556 EmpName: Richard; Address: San Diego
IT
Employees
Sales
Employ
ees
E
M
P
L
O
Y
E
E
S
No sql paradigm - Grouping
U123: O111Product Ids: [“Surface”,
“xbox”]U124:O123 Product Ids: [“Win 8”, “xbox”]
U124:O234 Product Ids: [“Win phone”, “surface”]
U124:O999Product Ids: [“office”, “azure
sub”]U125:O789
Product Ids: [“msdn”,
“office”]U125:O945
Product Ids: [“surface”,
“xbox”]
Colocation of a
users’ data.
GroupBy clause
No sql paradigm – Inverted search
& direct aggregation
EmpId, dept, city, …….
Dept-IT: [111, 123, 234….]
Dept-Sales:[673, 343, 434….]
City: Dallas
City: LA
111: Dept-Sales, City: LA …
222: Dept-IT, City: Dallas ….
No sql paradigm – Materialized
pathsElectronics
TV Phones Computers Cameras
Samsung Apple LG
LCD LED
No sql paradigm – Materialized
pathsTV
Samsung Apple LG
LCD LED
{ “entity”: “TV”,
“category”:”Electronics”}{ “entity”: “Samsung”, “category”:”Electronics, TV”}
{ “entity”: “Samsung”, “category”:”Electronics, TV, LCD”}
No sql paradigm – Nested sets
Electronics
TV Phones
Samsung Sony Cell Landline1 2 3 4 5 6 7 8 9 10 11 12 13 14
No sql paradigm – Nested sets
1 2 3 4 5 6 7 8 9 10 11 12 13
SonySamsung
TV
LandlineCell
Phone
Electronics
No sql paradigm : Flattening nested
documents
Name:
Chander
Hadoop: Expert
Nodejs: Expert
Spanish: Novice
{
“name”:”chander”,
“skills”:”hadoop, nodejs,
Spanish”,
“level”:”expert, expert,
novice”
}
Skills:hadoop AND
level:expert
No sql paradigm : Flattening nested
documents
Name: Chander
Hadoop: Expert
Nodejs: Expert
Spanish: Novice
{“name”:”chander”,“skills_1”:”hadoop”,“skills_2”: “nodejs”,“skills_3”: “spanish”, “level_1”:”expert”,“level_2”: “expert”,“level_3”: “novice”}
Search
78
Formatted results
79
Hypermedia
80
Resources
• http://chanderdhall.com/CodeCamp
• Twitter @csdhall
• http://apigee.com