KEMBAR78
REST Api Tips and Tricks | PPTX
RESTful APIs: Tips &
Tricks
Maksym Bruner
April 5, 2018
I am:
• Solution Architect in EPAM
• Java developer with 10+ years of experience
(also .NET, PHP)
• Kharkiv JUG Program Committee Head
• Bar owner
Who am I?
What do we need tests for?
1. Why it matters and what we won't talk about
2. Quick tips - one page you can easily find in Internet
3. What is hard to find in Internet
4. What is nearly impossible to find and what nobody likes to talk about
5. Tools, tools, tools
6. Modern approaches for communication between backend and frontend
Agenda
What do we need tests for?
• HATEOAS – never seen
• Management solutions – different focus
• Implementation details – takes to much time
Not today
•API (Application Programming Interface) is a
traditional and well known integration method.
An approach to represent Business or IT assets and enable
and enable programmatic access to them
•Recently, the term “API” often implies Web API:
“Web APIs are the defined interfaces through which
interactions happen between an enterprise and applications
applications that use its assets” - Wikipedia
•In business context APIs are seen as one of the pillars
of digital business: they help in building the
automated business ecosystems also known as
WHAT IS AN API?
GET statuses/mentions_timeline
GET statuses/user_timeline
GET statuses/retweets_of_me
GET statuses/retweets/:id
GET statuses/show/:id
POST statuses/destroy/:id
POST statuses/update
POST statuses/retweet/:id
01001
10110 CORE
BUSINESS
WHAT?
HOW?
API CLASSIFICATIONS: WHAT TYPES OF APIs EXIST?
▶ Data
▶ Processes
▶ Things
ASSETS
▶ Private
▶ Partner
▶ Public
SCOPE
▶ Free
▶ Developer pays
▶ Developer gets paid
▶ Indirect
BUSINESS
MODEL
▶ Based on specification or standard (e.g.
FHIR, OData)
▶ Unique, non-standard
STANDAR
DS
▶ SOAP
WEB
SERVICES
▶ Hypermedia
▶ Pragmatic REST
REST
▶ Websockets
▶ Comet
▶ Web hooks
EVENT-
DRIVEN
TECHNOL
OGY
Simple task:
Implement 3 tier application for saved search service:
• User submits a query
• System generates search results – saved search
• User can view submitted queries and then view
results
• User can archive or delete saved search
Three teams:
• Frontend
• Backend
• DevOps
Workshop
What could go wrong?
• Paths, methods
• Data models
• Input parameters
• Actions
• Security
Efforts:
• 1 hour for discussing happy-path scenarios
• 1 hour for discussing exceptional cases
QUICK WINS
1. Nouns
GET /requests
GET /requests/new
GET /getRequests
2. GET and state
GET /users/123/activate -> activate
3. Plural nouns
GET /users
GET /user
4. Subresources
GET /users/123/activities
What you can find easily on the Internet?
5. Headers
Content-Type: application/json
Accept: appication/json, application/xml
6. Sorting and filtering
GET /cars?color=red
GET /cars?sort=+name,-age
7. Select fields
GET /cars?fields=name,color
8. Paging
GET /cars?limit=0&offset=10
What else?
10. Field names
Use camelCase that is a standard for JSON
11. Use error codes
2xx – ok
3xx – redirection
4xx – client error
5xx – server error
12. Versioning
/v1/cars
13. Shortcuts
/requests/closed
/notifications/last
14. Use or not use wrappers
{
count: 10,
list: [..]
}
15. Defaults for pagination and filtering
16. Authentication
WHAT IS NOT SO CLEAR THERE
What must be considered during design:
• How simple is to understand and ”Clean” design
• How to secure URI
• Usage scenarios and domain
• Caching
• Overlapping with other URIs
• REST requirements
Scenarios:
• View my requests
• View my requests (Support team)
• View requests from my department (Manager)
URI Structures
GET /requests
GET /requests?user_id={user_id}
GET /{user_id}/requests
GET /users/{user_id}/requests
GET /requests
X-User-Identifier: {user_id}
GET /support/requests
GET /requests/my
Cache-Control: private
GET /me/requests
Cache-Control: private
GET /requests/1234
--------------------
HTTP/1.1 200 OK
{
id: “1234”,
subject: “Password expired”,
categoryId: “22”,
created: …,
status: “APPROVED”,
assignee: {
id: “4321”,
name: “Amit Kumar”
}
}
Data models
POST /requests
{
subject: “Password expired”,
categoryId: “22”
}
--------------------
HTTP/1.1 201 Created
Location:
http://example.org/requests/1234
{
id: “1234”,
…
}
PUT /requests/1234
{
!!!
}
--------------------
PATCH /requests/1234
{
subject: “Password is expired”
}
--------------------
PATCH /requests/1234
[
{ subject: “Password is expired” },
{ tags: “3,45,121” },
]
Data models #2
GET /requests/1234/edits
--------------------
[
{
date: “2018-04-04T14:20:25.912Z”,
author: {
id: “513”,
name: “Rajeev Jane”
},
changes: [
{ subject: “Password is expired” },
{ tags: “3,45,121” },
]
},…
]
Prefer header
Applicable for:
• Different content schemas for GET requests
• return-minimal
• return-full
• Different return objects
• return-content
• return-status
• return-no-content
• Versioning
• Free format responses
Data models #3
HTTP/1.1 201 Created
Location: http://example.org/requests/1234
{
id: “1234”,
…
}
HTTP/1.1 201 Created
Location: http://example.org/requests/1234
{
status: ”ok”
}
HTTP/1.1 204 No Content
Location: http://example.org/requests/1234
Take into account:
• Caching must be proxy aware
• Aggressive caching might happen
• Header that might affect response content
Additional directives:
• max-age=<seconds> – overrides Expires header
• must-revalidate – forces resources validation
Examples:
Cache-Control: no-cache, no-store, must-revalidate
Cache-Control: public, max-age=31536000
What is eligible for:
• GET and HEAD
• 200, 203, 206, 300, 301, 410
Caching API Calls
Cache-
Control
Local
cache
Cache
anywhere
Revalidati
on
no-store no no n/a
private yes no no
no-cache yes yes yes
public yes yes no
If-Modified-Since != Last-Modified = 200
If-Modified-Since == Last-Modified = 304
If-None-Match != Etag = 200
If-None-Match == Etag = 304
HTTP/1.1 200 OK
Etag: “1234-1”
Last-Modified: Sat, 27 Jun 2015 11:03:32 GMT
Authentication methods:
• Basic
Authorization: Basic ZnJlZDpmcmVk
• API Key
X-API-Key: abcdef12345
• OAuth
Authorization: Bearer
pwwbkvv7abqzonnvztpea91ich7vprwdorbt4w4m
• OAuth JWT tokens
• OAuth scopes: granularity for permissions
• 54 scopes used by Slack API
• users.profile:read,
• users.profile:write
Security
Code Description
400 Bad
Request
Request cannot be processed. Used when
request contains unsupported parameters.
Also, used for validation errors or wrong
input format indication.
401
Unauthorized
Request requires authentication.
403 Forbidden
Access is not allowed to a requested
resource or operation.
404 Not Found Resource was not found.
500 Internal
Server Error
Error happened on server side. Default
handlers that provides such details as a
stack trace in response MUST be avoided.
Error design (including validation)
{
code: 1234,
message: “Validation failed”,
errors: [
{
field: “referenceEntityId”,
errorMessage: “Not found”
},
{
field: “name”,
errorMessage: “Name is required”
}
]
}
Use Content-Type for different schemas:
• application/json;profile=NoBodyError
• application/json;profile=NoParameterError
• application/json;profile=ValidationError
What else can be included:
• Link to documentation
• Error description
WHAT IS HARD TO FIND
Take care of:
• All possible workflows
• Linked resources
• Actors
• Domain model
Design tips:
• Try treating actions as resources
• Use PATCH with complex payloads
• Use headers for meta information
Complex actions
Context: IT support system
Use cases:
1 Re-assign request
2 Enrich extra request information
3 Clone request
4 Grant permission to view requests
5 Transfer to another system
6 Merge requests
7 Lock/unlcok request
8 Change status
9 skip
1 Re-assign request
2 Enrich extra request information
3 Clone request
Complex actions #2
1. PATCH /requests/{request_id}
{
assigneeId: <new_id>,
}
2. PUT /requests/{request_id}/environment {
{
osVersion: "MAC OS X...",
hardware: {…},
destination: "EXTERNAL NETWORK",
...
}
3. POST /requests
Content-Type: application/reference
X-Reference-Id: <requst_id>
X-Clone-Parameters: copy-attachments
4 Grant permission to view
requests
5 Transfer to another system
Complex actions #3
4. PATCH /requests/{request_id}/acl
{ userId: <user_id>, permissions: "view,edit” }
5. POST /legacy_support/transfers
{ requestId: “1234” }
201 Created
{
transferId: "321",
status: "TRANSFERED",
originalRequestId: "1234",
legacyRequestId: "90189",
legacyLink: "http://old.support.company.net/requests/ID-
90189"
}
GET /legacy_support/requests/90189
301 Moved Permanently
Location: http://old.support.company.net/requests/ID-90189
6 Merge requests
7 Lock/unlock request
Complex actions #4
7. PATCH /requests/{request_id}/lock_status
{
locked: true,
details: { comment: "Lock for audit" }
}
GET /requests/{request_id}/lock_status
{
locked: true,
lockedBy: "John Doe"
since: "2018-04-04T14:20:25.912Z"
details: {
comment: "Lock for audit"
}
}
PATCH /requests/{request_id}/lock_status
{ locked: false }
8 Change status
Complex actions #5
7. PATCH /requests/{request_id}/status
{
status: "CLOSED",
details: {
resolution: "RESOLVED",
comment: "Password was reset"
}
}
GET /requests/{request_id}/status/history
[
{
status: "CLOSED",
date: "2018-04-04T14:20:25.912Z",
changedBy: "John Doe"
},
{
status: "IN_PROGRESS",
date: "2018-04-03T14:20:25.912Z",
changedBy: "John Doe"
},…
]
Limitations:
• URL length
• Copy link
• Durability
• Caching results (client/server)
Additional considerations:
• Saved presets
• Saved queries
Complex searches
1. GET /requests?name=param&status=SUBMITTED
2. GET /requests?filter={query}
3. POST /requests/search
{
author: "John",
status: "SUBMITTED"
}
201 Created
{
searchId: "9876",
expire: "2018-04-10T14:20:25.912Z"
}
GET /requests/search/9876?limit=15&offset=30
200 OK
X-Total-Count: 253
...
1. Resources
2. Methods
3. Response Codes
4. Tags
5. Models
Design steps
6. Complex Actions
7. Pagination & Sorting
8. Security
9. Error Models
10. Examples
1.Control and monitoring
• Control what you publish
• Throttling
• Control changes
2.Versioning
• Use hard versioning by including API version to requests
• Use soft versioning: change responses by manipulating
headers
Development
TOOLS
• Declarative schema definition
• UI support
• Validation
• New 3.0 version released last
year
• Code generation
Swagger or Open API
Swagger Hub
Swagger Diff
type Author {
id: Int!
firstName: String
lastName: String
posts: [Post]
}
type Post {
id: Int!
title: String
author: Author
votes: Int
}
type Query {
author(id: Int!): Author
}
GraphQL
query PostsForAuthor {
author(id: 1) {
firstName
posts {
title
votes
}}}
--------------------
{
"data": {
"author": {
"firstName": "Tom",
"posts": [
{ "title": "Introduction to GraphQL",
"votes": 2 }
]
}
}}
What next?
Workshop (1 day):
• Define business case
• Go through iterative process and design API
• 10 steps
• From scratch to comprehensive design
• Implement according to specification
• Code generation
• Spring adaptation
• Deployment and access
What next?
Questions?

REST Api Tips and Tricks

  • 1.
    RESTful APIs: Tips& Tricks Maksym Bruner April 5, 2018
  • 2.
    I am: • SolutionArchitect in EPAM • Java developer with 10+ years of experience (also .NET, PHP) • Kharkiv JUG Program Committee Head • Bar owner Who am I?
  • 3.
    What do weneed tests for? 1. Why it matters and what we won't talk about 2. Quick tips - one page you can easily find in Internet 3. What is hard to find in Internet 4. What is nearly impossible to find and what nobody likes to talk about 5. Tools, tools, tools 6. Modern approaches for communication between backend and frontend Agenda
  • 4.
    What do weneed tests for? • HATEOAS – never seen • Management solutions – different focus • Implementation details – takes to much time Not today
  • 5.
    •API (Application ProgrammingInterface) is a traditional and well known integration method. An approach to represent Business or IT assets and enable and enable programmatic access to them •Recently, the term “API” often implies Web API: “Web APIs are the defined interfaces through which interactions happen between an enterprise and applications applications that use its assets” - Wikipedia •In business context APIs are seen as one of the pillars of digital business: they help in building the automated business ecosystems also known as WHAT IS AN API? GET statuses/mentions_timeline GET statuses/user_timeline GET statuses/retweets_of_me GET statuses/retweets/:id GET statuses/show/:id POST statuses/destroy/:id POST statuses/update POST statuses/retweet/:id 01001 10110 CORE BUSINESS
  • 6.
    WHAT? HOW? API CLASSIFICATIONS: WHATTYPES OF APIs EXIST? ▶ Data ▶ Processes ▶ Things ASSETS ▶ Private ▶ Partner ▶ Public SCOPE ▶ Free ▶ Developer pays ▶ Developer gets paid ▶ Indirect BUSINESS MODEL ▶ Based on specification or standard (e.g. FHIR, OData) ▶ Unique, non-standard STANDAR DS ▶ SOAP WEB SERVICES ▶ Hypermedia ▶ Pragmatic REST REST ▶ Websockets ▶ Comet ▶ Web hooks EVENT- DRIVEN TECHNOL OGY
  • 7.
    Simple task: Implement 3tier application for saved search service: • User submits a query • System generates search results – saved search • User can view submitted queries and then view results • User can archive or delete saved search Three teams: • Frontend • Backend • DevOps Workshop What could go wrong? • Paths, methods • Data models • Input parameters • Actions • Security Efforts: • 1 hour for discussing happy-path scenarios • 1 hour for discussing exceptional cases
  • 8.
  • 9.
    1. Nouns GET /requests GET/requests/new GET /getRequests 2. GET and state GET /users/123/activate -> activate 3. Plural nouns GET /users GET /user 4. Subresources GET /users/123/activities What you can find easily on the Internet? 5. Headers Content-Type: application/json Accept: appication/json, application/xml 6. Sorting and filtering GET /cars?color=red GET /cars?sort=+name,-age 7. Select fields GET /cars?fields=name,color 8. Paging GET /cars?limit=0&offset=10
  • 10.
    What else? 10. Fieldnames Use camelCase that is a standard for JSON 11. Use error codes 2xx – ok 3xx – redirection 4xx – client error 5xx – server error 12. Versioning /v1/cars 13. Shortcuts /requests/closed /notifications/last 14. Use or not use wrappers { count: 10, list: [..] } 15. Defaults for pagination and filtering 16. Authentication
  • 11.
    WHAT IS NOTSO CLEAR THERE
  • 12.
    What must beconsidered during design: • How simple is to understand and ”Clean” design • How to secure URI • Usage scenarios and domain • Caching • Overlapping with other URIs • REST requirements Scenarios: • View my requests • View my requests (Support team) • View requests from my department (Manager) URI Structures GET /requests GET /requests?user_id={user_id} GET /{user_id}/requests GET /users/{user_id}/requests GET /requests X-User-Identifier: {user_id} GET /support/requests GET /requests/my Cache-Control: private GET /me/requests Cache-Control: private
  • 13.
    GET /requests/1234 -------------------- HTTP/1.1 200OK { id: “1234”, subject: “Password expired”, categoryId: “22”, created: …, status: “APPROVED”, assignee: { id: “4321”, name: “Amit Kumar” } } Data models POST /requests { subject: “Password expired”, categoryId: “22” } -------------------- HTTP/1.1 201 Created Location: http://example.org/requests/1234 { id: “1234”, … }
  • 14.
    PUT /requests/1234 { !!! } -------------------- PATCH /requests/1234 { subject:“Password is expired” } -------------------- PATCH /requests/1234 [ { subject: “Password is expired” }, { tags: “3,45,121” }, ] Data models #2 GET /requests/1234/edits -------------------- [ { date: “2018-04-04T14:20:25.912Z”, author: { id: “513”, name: “Rajeev Jane” }, changes: [ { subject: “Password is expired” }, { tags: “3,45,121” }, ] },… ]
  • 15.
    Prefer header Applicable for: •Different content schemas for GET requests • return-minimal • return-full • Different return objects • return-content • return-status • return-no-content • Versioning • Free format responses Data models #3 HTTP/1.1 201 Created Location: http://example.org/requests/1234 { id: “1234”, … } HTTP/1.1 201 Created Location: http://example.org/requests/1234 { status: ”ok” } HTTP/1.1 204 No Content Location: http://example.org/requests/1234
  • 16.
    Take into account: •Caching must be proxy aware • Aggressive caching might happen • Header that might affect response content Additional directives: • max-age=<seconds> – overrides Expires header • must-revalidate – forces resources validation Examples: Cache-Control: no-cache, no-store, must-revalidate Cache-Control: public, max-age=31536000 What is eligible for: • GET and HEAD • 200, 203, 206, 300, 301, 410 Caching API Calls Cache- Control Local cache Cache anywhere Revalidati on no-store no no n/a private yes no no no-cache yes yes yes public yes yes no If-Modified-Since != Last-Modified = 200 If-Modified-Since == Last-Modified = 304 If-None-Match != Etag = 200 If-None-Match == Etag = 304 HTTP/1.1 200 OK Etag: “1234-1” Last-Modified: Sat, 27 Jun 2015 11:03:32 GMT
  • 17.
    Authentication methods: • Basic Authorization:Basic ZnJlZDpmcmVk • API Key X-API-Key: abcdef12345 • OAuth Authorization: Bearer pwwbkvv7abqzonnvztpea91ich7vprwdorbt4w4m • OAuth JWT tokens • OAuth scopes: granularity for permissions • 54 scopes used by Slack API • users.profile:read, • users.profile:write Security
  • 18.
    Code Description 400 Bad Request Requestcannot be processed. Used when request contains unsupported parameters. Also, used for validation errors or wrong input format indication. 401 Unauthorized Request requires authentication. 403 Forbidden Access is not allowed to a requested resource or operation. 404 Not Found Resource was not found. 500 Internal Server Error Error happened on server side. Default handlers that provides such details as a stack trace in response MUST be avoided. Error design (including validation) { code: 1234, message: “Validation failed”, errors: [ { field: “referenceEntityId”, errorMessage: “Not found” }, { field: “name”, errorMessage: “Name is required” } ] } Use Content-Type for different schemas: • application/json;profile=NoBodyError • application/json;profile=NoParameterError • application/json;profile=ValidationError What else can be included: • Link to documentation • Error description
  • 19.
    WHAT IS HARDTO FIND
  • 20.
    Take care of: •All possible workflows • Linked resources • Actors • Domain model Design tips: • Try treating actions as resources • Use PATCH with complex payloads • Use headers for meta information Complex actions Context: IT support system Use cases: 1 Re-assign request 2 Enrich extra request information 3 Clone request 4 Grant permission to view requests 5 Transfer to another system 6 Merge requests 7 Lock/unlcok request 8 Change status 9 skip
  • 21.
    1 Re-assign request 2Enrich extra request information 3 Clone request Complex actions #2 1. PATCH /requests/{request_id} { assigneeId: <new_id>, } 2. PUT /requests/{request_id}/environment { { osVersion: "MAC OS X...", hardware: {…}, destination: "EXTERNAL NETWORK", ... } 3. POST /requests Content-Type: application/reference X-Reference-Id: <requst_id> X-Clone-Parameters: copy-attachments
  • 22.
    4 Grant permissionto view requests 5 Transfer to another system Complex actions #3 4. PATCH /requests/{request_id}/acl { userId: <user_id>, permissions: "view,edit” } 5. POST /legacy_support/transfers { requestId: “1234” } 201 Created { transferId: "321", status: "TRANSFERED", originalRequestId: "1234", legacyRequestId: "90189", legacyLink: "http://old.support.company.net/requests/ID- 90189" } GET /legacy_support/requests/90189 301 Moved Permanently Location: http://old.support.company.net/requests/ID-90189
  • 23.
    6 Merge requests 7Lock/unlock request Complex actions #4 7. PATCH /requests/{request_id}/lock_status { locked: true, details: { comment: "Lock for audit" } } GET /requests/{request_id}/lock_status { locked: true, lockedBy: "John Doe" since: "2018-04-04T14:20:25.912Z" details: { comment: "Lock for audit" } } PATCH /requests/{request_id}/lock_status { locked: false }
  • 24.
    8 Change status Complexactions #5 7. PATCH /requests/{request_id}/status { status: "CLOSED", details: { resolution: "RESOLVED", comment: "Password was reset" } } GET /requests/{request_id}/status/history [ { status: "CLOSED", date: "2018-04-04T14:20:25.912Z", changedBy: "John Doe" }, { status: "IN_PROGRESS", date: "2018-04-03T14:20:25.912Z", changedBy: "John Doe" },… ]
  • 25.
    Limitations: • URL length •Copy link • Durability • Caching results (client/server) Additional considerations: • Saved presets • Saved queries Complex searches 1. GET /requests?name=param&status=SUBMITTED 2. GET /requests?filter={query} 3. POST /requests/search { author: "John", status: "SUBMITTED" } 201 Created { searchId: "9876", expire: "2018-04-10T14:20:25.912Z" } GET /requests/search/9876?limit=15&offset=30 200 OK X-Total-Count: 253 ...
  • 26.
    1. Resources 2. Methods 3.Response Codes 4. Tags 5. Models Design steps 6. Complex Actions 7. Pagination & Sorting 8. Security 9. Error Models 10. Examples
  • 27.
    1.Control and monitoring •Control what you publish • Throttling • Control changes 2.Versioning • Use hard versioning by including API version to requests • Use soft versioning: change responses by manipulating headers Development
  • 28.
  • 29.
    • Declarative schemadefinition • UI support • Validation • New 3.0 version released last year • Code generation Swagger or Open API
  • 30.
  • 31.
  • 32.
    type Author { id:Int! firstName: String lastName: String posts: [Post] } type Post { id: Int! title: String author: Author votes: Int } type Query { author(id: Int!): Author } GraphQL query PostsForAuthor { author(id: 1) { firstName posts { title votes }}} -------------------- { "data": { "author": { "firstName": "Tom", "posts": [ { "title": "Introduction to GraphQL", "votes": 2 } ] } }}
  • 33.
    What next? Workshop (1day): • Define business case • Go through iterative process and design API • 10 steps • From scratch to comprehensive design • Implement according to specification • Code generation • Spring adaptation • Deployment and access What next?
  • 34.