Date post: | 11-Feb-2017 |
Category: |
Software |
Upload: | spencer-schneidenbach |
View: | 926 times |
Download: | 4 times |
#NeverRestRESTful API Design Best
PracticesUsing ASP.NET Web API
Spencer Schneidenbach
@schneidenbach
Why?@schneidenbach#NeverRest
Developers have the power of choice
@schneidenbach#NeverRest
Long-term benefits
@schneidenbach#NeverRest
Go from 0 to “make magic happen”
Learn stuff and manage exceptions
Developers have the power of choice
@schneidenbach#NeverRest
Developers have an opportunity create something better than the
competition
@schneidenbach#NeverRest
API Design is UX for Developers
@schneidenbach#NeverRest
This quote sums it up nicely
If you don’t make usability a priority, you’ll never have to worry about scalability.
-Kirsten Hunter @synedra
@schneidenbach#NeverRest
Some common themes
@schneidenbach#NeverRest
@schneidenbach#NeverRest
Simple != Easy
@schneidenbach#NeverRest
There’s No Silver Bullet
@schneidenbach#NeverRest
What is REST?
Representational State Transfer
@schneidenbach#NeverRest
Uniform InterfaceCode on Demand
(optional)Layered
StatelessCacheableClient-Server
The Six Constraints of REST
@schneidenbach#NeverRest
Resource identification
Uniform Interface constraint
Content-Type:
application/json
Resource manipulation with
representations
Self-descriptive Hypermedia as the engine of
application state (HATEOAS)
GET /employees/1234
PUT /employees/1234
@schneidenbach#NeverRest
What is a RESTful API?RESTful API == an API that follows REST architecture
Term has been sort of co-opted
REST != JSONREST != HTTP
Lots of people say “REST API” when they really mean HTTP JSON API
@schneidenbach#NeverRest
Pragmatic REST
RESTful API != Good API
@schneidenbach#NeverRest
Do what makes sense. Throw out the rest.
Is that vague enough for you?
@schneidenbach#NeverRest
MaintainDocument
ImplementDesign
API Design Process
@schneidenbach#NeverRest
Designing your RESTful APII HAVE ONE RULE… okay I actually have two rules
@schneidenbach#NeverRest
KISS(or, Keep it Simple, Stupid)
@schneidenbach#NeverRest
KISS
Don’t be creative.
Provide what is necessary – no more, no less.
Use a handful of HTTP status codes.
@schneidenbach#NeverRest
403 Forbidden(aka you can’t do that)
401 Unauthorized(aka not authenticated)
404 Not Found
400 Bad Request201 Created200 OK
Good HTTP Codes
@schneidenbach#NeverRest
KISS
{ "id": 1234, "active": true, "nameId": 345}
{ "id": 345, "name": "Acme"}
Customer API Name API
GET /customers/1234 GET /names/345
@schneidenbach#NeverRest
KISS
That’s TWO REQUESTS per GET
That’s TWO REQUESTS per POST
What’s the point?
@schneidenbach#NeverRest
Don’t let your specific implementations leak if they are
hard to use or understand.
@schneidenbach#NeverRest
KISS
{ "id": 1234, "active": true, "name": "Acme"}
Customer API
GET /customers/1234
@schneidenbach#NeverRest
KISS
TheoryAnnexThresholdLilia
@schneidenbach#NeverRest
KISSInactiveDeletedVisibleRetired
@schneidenbach#NeverRest
Second big rule – Be Consistent
Be consistent with accepted best practices.
Be consistent with yourself.
@schneidenbach#NeverRest
PATCHDELETE
POSTPUTGET
Understanding verbs
Remember consistency!@schneidenbach#NeverRest
Don’t mutate data with GETs.
@schneidenbach#NeverRest
Resource identificationNouns vs. verbs
Basically, use plural nouns
@schneidenbach#NeverRest
{ "invoices": [ { ... }, { ... } ]}
GET /customers/1234/invoic
es
GET /customers/1234?expand=invoices
Within the parent object
Sub-resource strategies
As a separate request Using an expand parameter
Be consistent, but be flexible when it makes sense
@schneidenbach#NeverRest
GET considerations
SortingFiltering
Paging@schneidenbach#NeverRest
Sorting/Ordering
$orderBy=name desc
$orderBy=name desc,hireDate
@schneidenbach#NeverRest
Filtering
$filter=(name eq 'Milk' or name eq 'Eggs') and price lt 2.55
@schneidenbach#NeverRest
Sorting and filtering for free
Google “OData web api”
@schneidenbach#NeverRest
PagingGET /customers? page=1 & pageSize=1000
{"pageNumber": 1,"results": [...],"nextPage": "/customers?page=2"
}
Good paging example on my blog: rest.schneids.net
@schneidenbach#NeverRest
Do I need to sort/page/filter?
Maybe!
What do your consumers need?
@schneidenbach#NeverRest
Versioning
Your APIs should stand a test of time
@schneidenbach#NeverRest
Versioning
GET /customersHost: contoso.comAccept: application/jsonX-Api-Version: 1
@schneidenbach#NeverRest
POST /customersHost: contoso.comAccept: application/jsonX-Api-Version: 2.0
Versioning
Use URL versioning@schneidenbach#NeverRest
GET /v1/customersHost: contoso.comAccept: application/json
Error reporting
Errors are going to happen.
How will you manage them?
@schneidenbach#NeverRest
Error reporting
{ "name": "Arana Software"}
@schneidenbach#NeverRest
Requires name and state
POST /vendors
400 Bad Request
Content-Type: application/json
"State is required."
{ "firstName": "Spencer"}
Requires first and last name
POST /employees
400 Bad Request
Content-Type: application/json
{
"errorMessage": "Your request was invalid."
}
Error reporting
@schneidenbach#NeverRest
Error reporting
Make finding and fixing errors as easy on your consumer as possible.
@schneidenbach#NeverRest
AuthenticationEncryption
Security
@schneidenbach#NeverRest
Use SSL.
Don’t roll your own encryption.
Pick an auth strategy that isn’t Basic.
@schneidenbach#NeverRest
Security
Ok, time for some code examplesand practical advise
@schneidenbach#NeverRest
@schneidenbach#NeverRest
Controller Anatomy
@schneidenbach#NeverRest
@schneidenbach#NeverRest
@schneidenbach#NeverRest
Use DTOs/per-request objects@schneidenbach#NeverRest
Separation of concerns
@schneidenbach#NeverRest
@schneidenbach#NeverRest
@schneidenbach#NeverRest
Separation of concerns
@schneidenbach#NeverRest
Controllers should know “where,” not ”how.”
@schneidenbach#NeverRest
Validation
@schneidenbach#NeverRest
Validation
Validate. Validate. Validate.
@schneidenbach#NeverRest
Separate validation logic from object.
Google Fluent Validation
Controller
Good Architecture
Request Handler/ServiceValidator
Enforce separation of concerns for maintainability and testability.
Google MediatR
Gotchas/ErrorsFormatting
SchemaParametersEndpoints
Documentation
@schneidenbach#NeverRest
Documentation
A good API lives and dies by its documentation.
(you should tweet that out)
@schneidenbach#NeverRest
Maintaining your APIVendor: “Hey, we’ve made some under-the-cover changes to our endpoint. It shouldn’t impact you, but let us know if it breaks something.”
Us: ”Okay. Can you release it to test first so we can run our integration tests against the endpoint and make sure everything works?”
Vendor: ”Well, actually we need it ASAP, so we’re releasing to prod in an hour.”
@schneidenbach#NeverRest
Maintaining your API
Fix bugs and optimize.
Don’t introduce breaking changes like removing properties.
@schneidenbach#NeverRest
Thank you!Slides, resources at rest.schneids.net
schneids.net
@schneidenbach