Matt Trask
@matthewtrask
Merge PHP - 04/14/2022
Matt Trask
@matthewtrask
Backend Team Lead
Ovia - @oviahealth
Podcast Host
APIs You Wont Hate & PHP Townhall
OSS Maintainer
openapi.tools | phptherightway.com
Matt Trask
@matthewtrask
This is a crash course in understanding REST with a focus on Concepts, URIs, Verbs, Status Codes, Headers.
Matt Trask
@matthewtrask
Before This Talk
Matt Trask
@matthewtrask
After This Talk
Matt Trask
@matthewtrask
Concepts
The Verbs
The Status Codes
The Headers
API Contracts and Tooling
Matt Trask
@matthewtrask
I want to break down the myth that REST is complicated.
Matt Trask
@matthewtrask
Concepts
URIs
The Verbs
The Status Codes
The Headers
API Contracts and Tooling
But first... some background.
Matt Trask
@matthewtrask
Matt Trask
@matthewtrask
Matt Trask
@matthewtrask
What do we mean by REST-ish?
Anything but full Hypermedia
Matt Trask
@matthewtrask
GET /characters
{
"action": "POST",
"data": {
"user": {
"id": 1,
"name": "Luke Skywalker",
"affilations": [
{
"Jedi",
"Rebels",
"Resistance"
}
]
}
}
}
Matt Trask
@matthewtrask
GET /star-wars-characters
{
"data": {
"user": {
{
"id": 1,
"name": "Luke Skywalker",
"affilations": [
{
"Jedi",
"Rebels",
"Resistance"
}
],
"roles": [
"star pilot",
"death star killer"
],
"weapon": "Lightsaber",
"friends": [
"Obi-Wan",
"Biggs Darklighter",
"Princess Leia",
"Chewie",
"Han Solo"
]
},
{
"id": 2,
"name": "Anakin Skywalker",
"affilations": [
{
"Jedi",
"Sith",
"Empire",
"Galatic Republic"
}
],
"roles": [
"general",
"star pilot",
"pod racing",
"youngling slayer"
],
"weapon": "Lightsaber",
"friends": [
"Obi-Wan",
"Palpatine",
"Ahsoka Tano",
"R2-D2",
"Captain Rex"
]
}
}
}
}
Matt Trask
@matthewtrask
GET /characters
200 OK
{
"error": "There were no characters to be found"
}
Matt Trask
@matthewtrask
Representation State Transfer (REST)
Matt Trask
@matthewtrask
6 Architectural Constraints
1. Client Server Architecture
2. Statelessness
3. Cacheability
4. Layered System
5. Code On Demand (optional)
6. Uniform Interface
Theorized in a doctoral thesis by Roy Fielding in 2000.
Matt Trask
@matthewtrask
1. Client Server Architecture
Client and Server are independent of each other.
Allows for independent
client (iOS, Android, Web) implementations.
Matt Trask
@matthewtrask
2. Statelessness
Server maintains intrinsic (resource) state
Client maintains extrinsic state, and is responsible for passing state to server (filters, limits, etc)
Matt Trask
@matthewtrask
3. Cacheability
Clients and intermediaries can cache responses.
Responses must, implicitly or explicitly, define themselves as cacheable or non-cacheable.
Matt Trask
@matthewtrask
4. Layered System
Client can not discern whether it has connected to the server directly, or through an intermediary like a proxy or load balancer
Matt Trask
@matthewtrask
5. Code On Demand
Ability to send code on demand, such as some Javascript, to the client to be executed.
*Optional
Matt Trask
@matthewtrask
6. Uniform Interface
1.Resource Identification in requests
2. Resource Manipulation Through Representations
3. Self-descriptive messages
4. Hypermedia as the engine of application state
*Fundamental
Matt Trask
@matthewtrask
Matt Trask
@matthewtrask
Out of those 6, the last one, mainly Hypermedia, is where most people struggle with REST
And it's super fixable!
Matt Trask
@matthewtrask
Concepts
URIs
The Verbs
The Status Codes
The Headers
API Contracts and Tooling
Matt Trask
@matthewtrask
Matt Trask
@matthewtrask
Matt Trask
@matthewtrask
The bane of every single developer
Mechanism to determine is remote origin is allowed to access local server assets or data
Matt Trask
@matthewtrask
Matt Trask
@matthewtrask
Hypermedia As The Engine Of Application State
Matt Trask
@matthewtrask
Hypermedia As The Engine Of Application State
Better described as:
Links and Discoverability
Matt Trask
@matthewtrask
GET /api/users
200 OK
Content-type: application/json
Etag: 0bba161a7165a211c7435c950ee78438
Cache-control: max-age=3600 // 1 hour
{
"data": [
{
"id": 1,
"name": "Luke Skywalker",
"links": {
"rel": "self",
"href": "/api/users/1",
"metbod": "GET"
}
},
{
"id": 2,
"name": "Anakin Skywalker",
"links": {
"rel": "self",
"href": "/api/users/2",
"method": "GET"
}
}
]
}
Matt Trask
@matthewtrask
GET /api/users/2
200 OK
Content-type: application/json
Etag: 0bba161a7165a211c7435c950ee78438
Cache-control: max-age=3600 // 1 hour
{
{
"id": 2,
"name": "Anakin Skywalker",
"roles": [
"general",
"star pilot",
"pod racing",
"youngling slayer"
]
"affiliation": [
"jedi",
"galatic republic",
"sith",
"empire"
],
"links": [
{
"rel": "affliation",
"href": "/api/users/2/affiliations",
"method": "GET"
},
{
"rel": "roles",
"href": "/api/users/2/roles",
"method": "GET"
},
{
"rel": "self",
"href": "/api/users/2",
"method": "PUT"
}
]
}
}
Matt Trask
@matthewtrask
Matt Trask
@matthewtrask
HTTP Basic - username & password
API Keys - random generated string, authentication only
OAuth - handles both authentication and authorization
Matt Trask
@matthewtrask
Authentication proves you are who you say you are.
Authorization says you can do what you are trying to do.
Matt Trask
@matthewtrask
Concepts
URIs
The Verbs
The Status Codes
The Headers
API Contracts and Tooling
Matt Trask
@matthewtrask
The Entry Point to your API
Best Practices
Resource Based instead Action Based
Pluralized
Hyphened instead of underscored
URIs should describe relationships
Use UUIDs for public API ids
Matt Trask
@matthewtrask
What does resource based mean?
Resource based means that by looking at the URI, I can reasonably determine what resource I am about to consume/manipulate/remove
Also allows you to manage relationships in the resource collection
Matt Trask
@matthewtrask
GOOD https://api.starwars.com/characters
BAD https://api.starwars.com/get_characters
GOOD https://api.starwars.com/characters/ac5b605a-661e-4083-857f-d65e30e3467a
tip: you dont need to use the full uuid
BAD https://api.starwars.com/characters/1
Matt Trask
@matthewtrask
GET https://api.fancypantsbank.com/accounts
GET https://api.fancypantsbank.com/accounts/1
POST https://api.fancypantsbank.com/accounts
PUT https://api.fancypantsbank.com/accounts/1
DELETE https://api.fancypantsbank.com/accounts/1
GET https://api.fancypantsbank.com/accounts/1/savings-account
POST https://api.fancypantsbank.com/accounts/1/savings-account
PUT https://api.fancypantsbank.com/accounts/1/savings-account
DELETE https://api.fancypantsbank.com/accounts/1/savings-account
Matt Trask
@matthewtrask
Concepts
URIs
The Verbs
The Status Codes
The Headers
API Contracts and Tooling
Matt Trask
@matthewtrask
Get
Post
Put
Patch
Delete
Options
Matt Trask
@matthewtrask
requests a representation of the specified resource
No Request Body
Response will have body
Safe
Idempotent
Cacheable
Matt Trask
@matthewtrask
GET /api/users
200 OK
Content-type: application/json
Etag: 0bba161a7165a211c7435c950ee78438
Cache-control: max-age=3600 // 1 hour
{
"data": [
{
"id": 1,
"name": "Luke Skywalker",
"links": {
"rel": "self",
"href": "/api/users/1",
"metbod": "GET"
}
},
{
"id": 2,
"name": "Anakin Skywalker",
"links": {
"rel": "self",
"href": "/api/users/2",
"method": "GET"
}
}
]
}
Matt Trask
@matthewtrask
send data to the server to create a resource
Request has body
Response may have body
Not Safe
Not Idempotent
Cacheable If Freshness Headers is provided
Matt Trask
@matthewtrask
POST /api/users
{
"name": "Wedge Antilles",
"species": "Corellian",
"age": 26,
"affiliations": [
"rebels",
"resistance"
],
"callsign": "Red 2"
"ship": "X-Wing"
}
201 Created
Location: /api/users/3
Content-Location: /api/users/3
Last-Modified: Wed, 24 Mar 2021 12:00:00 GMT
Matt Trask
@matthewtrask
update or create data on the server
Request will have a body
Successful response will not have body
Not Safe
Idempotent
Not cacheable
Status Codes: 201, 204
Matt Trask
@matthewtrask
PUT /api/users/3
{
"name": "Wedge Antilles",
"species": "Corellian",
"age": 30,
"affiliations": [
"rebels",
"resistance"
],
"callsign": "Red Leader"
"ship": "X-Wing"
}
200 OK
Location: /api/users/3
Content-Location: /api/users/3
Last-Modified: Mon, 15 Nov 2017 12:00:00 GMT
Matt Trask
@matthewtrask
partial update of a resource on a server
Request will have a body
Response may have body
Not Safe
Not Idempotent
Cacheable If Freshness Data is provided
May be restricted via headers
Status Codes: 200, 204
Matt Trask
@matthewtrask
PATCH /api/users/3
{
"callsign": "Red Leader"
}
204 No Content
Location: /api/users/3
Content-Location: /api/users/3
Last-Modified: Wed, 24 Mar 2021 12:01:00 GMT
Matt Trask
@matthewtrask
complete removal of a resource on a server
Request may have body
Response may have body
Not Safe
Not Idempotent
Cacheable If Freshness Data is provided
Status Codes: 200, 202, 204
Matt Trask
@matthewtrask
DELETE /api/users/3
{
"name": "Wedge Antilles",
"species": "Corellian",
"age": 30,
"affiliations": [
"rebels",
"resistance"
],
"callsign": "Red Leader"
"ship": "X-Wing"
}
204 No Content
200 OK
{
"message": "Resource deleted",
}
Matt Trask
@matthewtrask
requests permitted communication options for a given URL or server
Request will not have body
Response will have body
Safe
Idempotent
Not cacheable
Status Codes: 204
Matt Trask
@matthewtrask
Non-CORS
OPTIOMS /api/users
HTTP/1.1 204 No Content
Allow: OPTIONS, GET, HEAD, POST
Cache-Control: max-age=604800
Date: Wed, 24 Mar 2021 11:45:00 GMT
Server: EOS (lax004/2813)
CORS
OPTIONS https://starwars.com/api/users/ HTTP/1.1
Host: bar.example
Accept: text/html,application/xhtml+xml,application/json,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin: https://starwars.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type
Matt Trask
@matthewtrask
Concepts
URIs
The Verbs
The Status Codes
The Headers
API Contracts and Tooling
Matt Trask
@matthewtrask
Numbers and Phrases to give quick context for a request
// brew install httpie
http https://www.matthewtraskphotography.com
HTTP/1.1 200 OK
Matt Trask
@matthewtrask
100s - Informational
Matt Trask
@matthewtrask
200s - Success
Matt Trask
@matthewtrask
300s - Redirection
Matt Trask
@matthewtrask
400s - Client Errors
Matt Trask
@matthewtrask
500s - Server Error
Matt Trask
@matthewtrask
They aren't Pokemon, so you dont need to catch them all.
Matt Trask
@matthewtrask
100 Continue
Matt Trask
@matthewtrask
103 Early Hints
Matt Trask
@matthewtrask
200 OK
Appropriate Verbs: GET, PUT, PATCH, OPTIONS, DELETE
Matt Trask
@matthewtrask
201 Created
Appropriate Verbs: POST, PUT
Matt Trask
@matthewtrask
202 Accepted
Appropriate Verbs: POST, PUT, PATCH, DELETE
Matt Trask
@matthewtrask
204 No Content
Appropriate Verbs: DELETE, GET
Matt Trask
@matthewtrask
206 Partial Content
not real pizza btw
Appropriate Verbs: GET
Matt Trask
@matthewtrask
301 Moved Permanently
Matt Trask
@matthewtrask
304 Not Modified
Headers (one must be present): Cache-control, Content-location, Etag, Date, Expires, Vary
Matt Trask
@matthewtrask
307 Temporary Redirect
Matt Trask
@matthewtrask
308 Permanent Redirect
Server should add a Location header
Matt Trask
@matthewtrask
401 Unauthorized
Matt Trask
@matthewtrask
403 Forbidden
Matt Trask
@matthewtrask
406 Not Acceptable
Matt Trask
@matthewtrask
409 Conflict
Matt Trask
@matthewtrask
411 Length Required
Matt Trask
@matthewtrask
410 Gone
Matt Trask
@matthewtrask
413 Payload Too Large
If time based restriction, server should send Retry-after header
Matt Trask
@matthewtrask
418 I'm a teapot
Matt Trask
@matthewtrask
429 Too Many Requests
Matt Trask
@matthewtrask
451 Unavailable for legal reasons
Matt Trask
@matthewtrask
501 Not Implemented
Matt Trask
@matthewtrask
503 Service Unavailable
Matt Trask
@matthewtrask
505 HTTP Version Not Supported
Matt Trask
@matthewtrask
Concepts
URIs
The Verbs
The Status Codes
The Headers
API Contracts and Tooling
Matt Trask
@matthewtrask
Information sent with the request and response
4 Types of Headers
General Headers
Request Headers
Response Headers
Entity Headers
Matt Trask
@matthewtrask
Accept | Content-type
# Request
Accept: application/json
Accept: application/vnd.github+json
Accept: application/xml
Accept: text/plain
Accept: text/csv
# Response
Content-type: application/json
Content-type: text/html
Content-type: text/csv
Content-type: application/vnd.github+json
These headers allow for content negotiation: where the server decides between the mime types which is best to send
Matt Trask
@matthewtrask
Authorization
# Request
Authorization: Bearer 5eb63bbbe01eeed093cb22bb8f5acdc3
Authorization: Basic a94a8fe5ccb19ba61c4c0873d391e987982fbbd3
Matt Trask
@matthewtrask
Cache-Control
# Request
Cache-Control: max-age=<seconds>
Cache-Control: max-stale[=<seconds>]
Cache-Control: min-fresh=<seconds>
Cache-Control: no-cache
Cache-Control: no-store
Cache-Control: no-transform
Cache-Control: only-if-cached
# Response
Cache-Control: no-cache
Cache-Control: no-store
Cache-Control: no-transform
Cache-Control: public
Cache-Control: private
Cache-Control: proxy-revalidate
Cache-Control: max-age=<seconds>
Cache-Control: s-maxage=<seconds>
Matt Trask
@matthewtrask
Location
# Response
Content-Location: /api/characters/3
Location: /api/characters/3
Matt Trask
@matthewtrask
Etag | Age | Last-Modified
# Response
Etag: 5eb63bbbe01eeed093cb22bb8f5acdc3
Age: 60 // in seconds
Last-modified: Wed, 24 Mar 2021-03-24 12:00:00 GMT // “HTTP-date” format as defined by RFC 7231
Matt Trask
@matthewtrask
Content-length | Content-language | Expires
# Response
Content-length: 128 // represented by 8-bit bytes
Content-language: en
Expires: Tue, 29 Mar 2021 23:59:59 GMT
Matt Trask
@matthewtrask
CORS
Access-Control-Allow-Origin
Access-Control-Allow-Credentials
Access-Control-Expose-Headers
Access-Control-Max-Age
Access-Control-Allow-Methods
Access-Control-Allow-Headers
Matt Trask
@matthewtrask
Concepts
URIs
The Verbs
The Status Codes
The Headers
API Contracts and Tooling
Matt Trask
@matthewtrask
Matt Trask
@matthewtrask
What Is An API Contract?
It is something that both API provider and API consumer can agree upon, and get to work developing and delivering, and then integrating and consuming. An API contract is a shared understanding of what the capabilities of a digital interface are, allowing for applications to be programmed on top of.
Matt Trask
@matthewtrask
A description language that allows for documentation generation, testing, SDK generation, and more.
The resulting file creates the "contract" that both the server and client can reliable consume.
The artist formerly known as Swagger
Matt Trask
@matthewtrask
Matt Trask
@matthewtrask
Matt Trask
@matthewtrask
https://github.com/matthewtrask/national-parks-api/blob/main/contract/openapi.yml
Matt Trask
@matthewtrask
Matt Trask
@matthewtrask
JSON Schema is a vocabulary that allows you to annotate and validate JSON documents.
Matt Trask
@matthewtrask
{
"$id": "https://example.com/address.schema.json",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"description": "An address similar to http://microformats.org/wiki/h-card",
"type": "object",
"properties": {
"post-office-box": {
"type": "string"
},
"extended-address": {
"type": "string"
},
"street-address": {
"type": "string"
},
"locality": {
"type": "string"
},
"region": {
"type": "string"
},
"postal-code": {
"type": "string"
},
"country-name": {
"type": "string"
}
},
"required": [ "locality", "region", "country-name" ],
"dependentRequired": {
"post-office-box": [ "street-address" ],
"extended-address": [ "street-address" ]
}
}
Matt Trask
@matthewtrask
OpenAPI 3.1 finally worked through some minor issues and now OpenAPI and JSON Schema play nice together!
Matt Trask
@matthewtrask
Postman - HTTP Testing
Paw (Mac Only) - HTTP Testing
HTTPie (CLI) - HTTP Testing
Insomnia - HTTP Testing
Postwoman - HTTP Testing
Stoplight Studio - Documentation
Stoplight Spectral - Linting
Dredd.io - Testing
jq - CLI JSON map/filter/slice
Matt Trask
@matthewtrask
APIs You Wont Hate (book, blog, podcast)
API Evangelist (blog)
Nordic APIs (blog, events)
People to follow:
Phil Sturgeon (OpenAPI/Loud Person) @philsturgeon
Ben Hutton (JSON Schema) @benhutton
Kin Lane @apievangelist
Darrel Miller (OpenAPI TSC) @darrelmiller
Mike Amundsen @mamund
Arnaud Lauret @apihandyman
Mike Ralphson (OpenAPI TSC) @permittedsoc
Matt Trask
@matthewtrask
@matthewtrask | mjftrask@gmail.com
podcast: apis you wont hate
apisyouwonthate.com | matthewtrask.net