RESTful API Design Best Practices Using ASP.NET Web API

Post on 11-Feb-2017

922 Views

Category:

Software

4 Downloads

Preview:

Click to see full reader

Transcript

#NeverRestRESTful API Design Best

PracticesUsing ASP.NET Web API

Spencer Schneidenbach

@schneidenbach

Slides, links, and more at rest.schneids.net

@schneidenbach#NeverRest

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

top related