Slide 1

Slide 1 text

Tue, 22 Oct | 11:30 AM – 12:20 PM Beta Room Spencer Schneidenbach
 RESTful API Best Practices Using ASP.NET Core

Slide 2

Slide 2 text

Slides, links, and more at rest.schneids.net @schneidenbach #NeverRest

Slide 3

Slide 3 text

Why? @schneidenbach #NeverRest

Slide 4

Slide 4 text

@schneidenbach #NeverRest

Slide 5

Slide 5 text

@schneidenbach #NeverRest

Slide 6

Slide 6 text

API Design is UX for Developers @schneidenbach #NeverRest

Slide 7

Slide 7 text

Some common themes @schneidenbach #NeverRest

Slide 8

Slide 8 text

@schneidenbach #NeverRest

Slide 9

Slide 9 text

Simple != Easy @schneidenbach #NeverRest

Slide 10

Slide 10 text

There’s No Silver Bullet @schneidenbach #NeverRest

Slide 11

Slide 11 text

What is REST? Representational State Transfer @schneidenbach #NeverRest

Slide 12

Slide 12 text

Uniform Interface Code on Demand (optional) Layered Stateless Cacheable Client-Server The Six Constraints of REST @schneidenbach #NeverRest

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

What is a RESTful API? RESTful API == an API that follows REST architecture Term has been sort of co-opted REST != JSON REST != HTTP Lots of people say “REST API” when they really mean HTTP JSON API @schneidenbach #NeverRest

Slide 15

Slide 15 text

Pragmatic REST RESTful API != Good API @schneidenbach #NeverRest

Slide 16

Slide 16 text

Do what makes sense. Throw out the rest. Is that vague enough for you? @schneidenbach #NeverRest

Slide 17

Slide 17 text

Maintain Document Implement Design API Design Process @schneidenbach #NeverRest

Slide 18

Slide 18 text

Designing your RESTful API I HAVE ONE RULE… okay I actually have TWO RULES @schneidenbach #NeverRest

Slide 19

Slide 19 text

KISS (or, Keep it Simple, Stupid) @schneidenbach #NeverRest

Slide 20

Slide 20 text

KISS Don’t be creative. Provide what is necessary – no more, no less. Use a handful of HTTP status codes. @schneidenbach #NeverRest

Slide 21

Slide 21 text

403 Forbidden (aka you can’t do that) 401 Unauthorized (aka not authenticated) 404 Not Found 400 Bad Request 201 Created 200 OK Good HTTP Codes @schneidenbach #NeverRest

Slide 22

Slide 22 text

KISS { "id": 1234, "active": true, "nameId": 345 } { "id": 345, "name": "Acme" } Customer API Name API GET /customers/1234 GET /names/345 @schneidenbach #NeverRest

Slide 23

Slide 23 text

KISS That’s TWO REQUESTS per GET That’s TWO REQUESTS per POST What’s the point? @schneidenbach #NeverRest

Slide 24

Slide 24 text

Don’t let your specific implementations leak if they are hard to use or understand. @schneidenbach #NeverRest

Slide 25

Slide 25 text

KISS { "id": 1234, "active": true, "name": "Acme" } Customer API GET /customers/1234 @schneidenbach #NeverRest

Slide 26

Slide 26 text

KISS Inactive Deleted Visible Retired @schneidenbach #NeverRest

Slide 27

Slide 27 text

@schneidenbach #NeverRest

Slide 28

Slide 28 text

@schneidenbach #NeverRest

Slide 29

Slide 29 text

Second big rule – Be Consistent Be consistent with accepted best practices. Be consistent with yourself. @schneidenbach #NeverRest

Slide 30

Slide 30 text

PATCH DELETE POST PUT GET Understanding verbs Remember consistency! @schneidenbach #NeverRest

Slide 31

Slide 31 text

Don’t mutate data with GETs. @schneidenbach #NeverRest

Slide 32

Slide 32 text

Resource identification Nouns vs. verbs Basically, use plural nouns @schneidenbach #NeverRest

Slide 33

Slide 33 text

{ "invoices": [ { ... }, { ... } ] } GET /customers/1234/ invoices 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

Slide 34

Slide 34 text

GET considerations Sorting Filtering Paging @schneidenbach #NeverRest

Slide 35

Slide 35 text

Sorting/Filtering GET /customers?name=Spencer @schneidenbach #NeverRest

Slide 36

Slide 36 text

Paging GET /customers? page=1 & pageSize=1000 { "pageNumber": 1, "results": [...], "nextPage": "/customers?page=2" } @schneidenbach #NeverRest Good paging example on my website: rest.schneids.net

Slide 37

Slide 37 text

Do I need to sort/page/filter? Maybe! What do your consumers need? @schneidenbach #NeverRest

Slide 38

Slide 38 text

Versioning Your APIs should stand a test of time @schneidenbach #NeverRest

Slide 39

Slide 39 text

Versioning GET /customers Host: contoso.com Accept: application/json X-Api-Version: 1 @schneidenbach #NeverRest POST /customers Host: contoso.com Accept: application/json X-Api-Version: 2.0

Slide 40

Slide 40 text

Versioning Use URL versioning @schneidenbach #NeverRest GET /v1/customers Host: contoso.com Accept: application/json

Slide 41

Slide 41 text

Error reporting Errors are going to happen. How will you manage them? @schneidenbach #NeverRest

Slide 42

Slide 42 text

Error reporting { "name": "Aviron Software" } @schneidenbach #NeverRest { "firstName": "Spencer" } Requires first and last name POST /employees 400 Bad Request Content-Type: application/json { "errorMessage": "Your request was invalid." } Requires name and state POST /vendors 400 Bad Request Content-Type: application/json "State is required."

Slide 43

Slide 43 text

Error reporting @schneidenbach #NeverRest

Slide 44

Slide 44 text

Error reporting Make finding and fixing errors as easy on your consumer as possible. @schneidenbach #NeverRest

Slide 45

Slide 45 text

Authentication Encryption Security @schneidenbach #NeverRest

Slide 46

Slide 46 text

Use SSL. Don’t roll your own encryption. Pick an auth strategy that isn’t Basic. @schneidenbach #NeverRest Security

Slide 47

Slide 47 text

Ok, time for some code examples and practical advise @schneidenbach #NeverRest

Slide 48

Slide 48 text

Typical controller @schneidenbach #NeverRest

Slide 49

Slide 49 text

@schneidenbach #NeverRest

Slide 50

Slide 50 text

@schneidenbach #NeverRest

Slide 51

Slide 51 text

@schneidenbach #NeverRest

Slide 52

Slide 52 text

Separation of concerns @schneidenbach #NeverRest Controllers should know “where,” not ”how.” Enter MediatR

Slide 53

Slide 53 text

No content

Slide 54

Slide 54 text

No content

Slide 55

Slide 55 text

@schneidenbach #NeverRest

Slide 56

Slide 56 text

Validation Validate. Validate. Validate. @schneidenbach #NeverRest Separate validation logic from object. Google Fluent Validation

Slide 57

Slide 57 text

No content

Slide 58

Slide 58 text

No content

Slide 59

Slide 59 text

Controller Good Architecture Request Handler/Service Validator Enforce separation of concerns for maintainability and testability.

Slide 60

Slide 60 text

Just remember to use all these things • MediatR • Fluent Validation • Autofac • Microsoft DI • Entity Framework • AutoMapper or…

Slide 61

Slide 61 text

rest.schneids.net

Slide 62

Slide 62 text

No content

Slide 63

Slide 63 text

Gotchas/Errors Formatting Schema Parameters Endpoints Documentation @schneidenbach #NeverRest

Slide 64

Slide 64 text

Documentation A good API lives and dies by its documentation. (you should tweet that out) @schneidenbach #NeverRest

Slide 65

Slide 65 text

Maintaining your API Vendor: “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

Slide 66

Slide 66 text

@schneidenbach #NeverRest

Slide 67

Slide 67 text

Maintaining your API Fix bugs and optimize. Don’t introduce breaking changes like removing properties. @schneidenbach #NeverRest

Slide 68

Slide 68 text

Thank you! Slides, resources at rest.schneids.net schneids.net @schneidenbach

Slide 69

Slide 69 text

Session Feedback
 Your Time & Opinion is Valued
 https://www.telerik.com/devreach/day1feedback