Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Return to REST (PHP Tek 2025)

Return to REST (PHP Tek 2025)

We don't talk about REST much these days. Why is that? Was REST too hard? Did we get tired of it? Did GraphQL win?

Let's revisit REST to learn how its concepts can be put into practice to build great APIs. Along the way, we'll talk about some of the criticisms of REST and why GraphQL is an attractive alternative. We'll also discuss when it's okay to bend or break the rules, and we'll cover hypermedia, content negotiation, and API versioning pitfalls.

Avatar for Ben Ramsey

Ben Ramsey

May 21, 2025
Tweet

More Decks by Ben Ramsey

Other Decks in Programming

Transcript

  1. • Identi fi cation of resources • Manipulation of resources

    through representations • Self-descriptive messages • Hypermedia as the engine of application state 4. Uniform interface
  2. Representational State Transfer 1. Client/server 2. Stateless 3. Cache 4.

    Uniform interface 5. Layered system 6. Code on demand REST
  3. An architecture that is… • Loosely coupled • Simple •

    Evolvable • Portable • Reliable • Scalable REST
  4. • We’re humans • We’re lazy • We need this

    yesterday. • We don’t plan for the future. • REST requires investments. • We all suck.
  5. • Reduces number of network requests and amount of data

    transferred • From a company whose motto was once “move fast and break things” • The primary trade-o ff : extreme tight coupling GraphQL
  6. HTTP/1.1 200 OK Date: Sat, 10 Oct 2024 16:31:57 GMT

    Content-Length: 23 { "status": "success" } POST /rpc.php HTTP/1.1 Host: api.example.com Content-Length: 125 { "method": "saveCampaignData", "params": { "email": "[email protected]", "postalCode": "12345" } } Request Response
  7. HTTP/1.1 200 OK Date: Sat, 10 Oct 2024 16:31:57 GMT

    Content-Length: 23 { "status": "success" } GET /record/create? campaignID=o0zJeEcJ &[email protected] &postalCode=12345 HTTP/1.1 Host: api.example.com Request Response
  8. HTTP/1.1 200 OK Date: Sat, 10 Oct 2024 16:43:23 GMT

    Content-Length: 120 { "records": [{ "email": "[email protected]", "postalCode": "12345" }] } GET /campaign/o0zJeEcJ HTTP/1.1 Host: api.example.com Request Response
  9. • Use proper HTTP semantics for resources • POST to

    create a new record, GET to fetch a campaign • What else can we do with that campaign resource? • Create new campaigns with POST • Update campaigns with PUT • What about the record? • Fetch an individual record with GET • Use PATCH to partially update a record
  10. HTTP/1.1 200 OK Date: Sat, 10 Oct 2024 17:14:11 GMT

    Content-Length: 67 { "campaignId": "o0zJeEcJ", "name": "My Awesome Campaign" } POST /campaign HTTP/1.1 Host: api.example.com Content-Length: 37 { "name": "My Awesome Campaign" } Request Response
  11. HTTP/1.1 200 OK Date: Sat, 10 Oct 2024 17:22:04 GMT

    Content-Length: 173 { "campaignId": "o0zJeEcJ", "name": "Totally Rad Campaign", "startDate": "2015-09-06T18:12:47+00:00", "endDate": "2015-10-06T18:13:06+00:00" } PUT /campaign/o0zJeEcJ HTTP/1.1 Host: api.example.com Content-Length: 143 { "campaignId": "o0zJeEcJ", "name": "Totally Rad Campaign", "startDate": "2015-09-06T18:12:47+00:00", "endDate": "2015-10-06T18:13:06+00:00" } Request Response
  12. HTTP/1.1 200 OK Date: Sat, 10 Oct 2024 17:28:45 GMT

    Content-Length: 119 { "recordId": "5s7ytJlT", "campaignID": "o0zJeEcJ", "email": "[email protected]", "postalCode": "12345" } POST /record HTTP/1.1 Host: api.example.com Content-Length: 91 { "campaignID": "o0zJeEcJ", "email": "[email protected]", "postalCode": "12345" } Request Response
  13. HTTP/1.1 200 OK Date: Sat, 10 Oct 2024 17:29:31 GMT

    Content-Length: 119 { "recordId": "5s7ytJlT", "campaignID": "o0zJeEcJ", "email": "[email protected]", "postalCode": "12345" } GET /record/5s7ytJlT HTTP/1.1 Host: api.example.com Request Response
  14. HTTP/1.1 200 OK Date: Sat, 10 Oct 2024 17:28:45 GMT

    Content-Length: 123 { "recordId": "5s7ytJlT", "campaignID": "o0zJeEcJ", "email": "[email protected]", "postalCode": "12345" } PATCH /record/5s7ytJlT HTTP/1.1 Host: api.example.com Content-Length: 38 { "email": "[email protected]" } Request Response
  15. Level 0: The Swamp of POX Level 1: Resources Level

    2: HTTP Verbs Level 3: Hypermedia
  16. HTTP/1.1 201 Created Date: Sat, 10 Oct 2024 17:45:27 GMT

    Content-Type: application/hal+json Content-Length: 838 Location: /campaign/o0zJeEcJ POST /campaign HTTP/1.1 Host: api.example.com Accept: application/hal+json Content-Type: application/json Content-Length: 37 { "name": "My Awesome Campaign" } Request Response
  17. { "_links": { "self": { "href": "https://api.example.com/campaign/o0zJeEcJ" }, "curies": [{

    "name": "ex", "href": "https://api.example.com/docs/rels/{rel}", "templated": true }], "ex:campaigns": { "href": "https://api.example.com/campaign/" }, "ex:records": { "href": "https://api.example.com/record/" } }, "name": "My Awesome Campaign", "_embedded": { "ex:record": [{ "_links": { "self": { "href": "https://api.example.com/record/5s7ytJlT" }, "ex:campaign": { "href": "https://api.example.com/campaign/o0zJeEcJ" } }, "email": "[email protected]", "postalCode": "12345" }] } }
  18. In a nutshell • Use links to provide relationships between

    resources • Use media types to describe how to process a representation Hypermedia
  19. Benefits • Clients discover locations and operations • Link relations

    express possible options • URLs can change • Work fl ow is abstracted • Media type can be versioned • Clients do not break if the implementation is updated! Hypermedia
  20. It answers these questions • How does a client know

    what to do with resources? • How do you go to the “next” operation? • What are the URLs for creating subordinate resources? • Where is the contract for the service? Hypermedia
  21. • Use HTTP methods for the purpose they were created:

    • GET, POST, PUT, PATCH, DELETE, BREW… • Uniquely identify each resource with a URI. • Be self-documenting through headers (e.g., Accept, Allow, Link, etc.) • Use hypermedia (links)! • Put thought into your media types.
  22. HTTP/1.1 200 OK Date: Sat, 10 Oct 2024 17:28:45 GMT

    Accept: application/hal+json Allow: GET, PUT, PATCH, DELETE, OPTIONS, HEAD Link: </record/5s7ytJlT>; rel="self" Link: </record>; rel="collection" Link: </campaign/o0zJeEcJ>; rel="https://example.com/rel/campaign" OPTIONS /record/5s7ytJlT HTTP/1.1 Host: api.example.com Request Response
  23. HTTP/1.1 200 OK Date: Sat, 10 Oct 2024 17:28:45 GMT

    Accept: application/hal+json Allow: GET, POST, OPTIONS, HEAD Link: </record>; rel="self" Link: </record>; rel="start" Link: </record?page=2>; rel="next" Link: </record?page=1234>; rel="last" OPTIONS /record HTTP/1.1 Host: api.example.com Request Response
  24. Roy T. Fielding “If you think you have control over

    the system or aren’t interested in evolvability, don’t waste your time arguing about REST.”
  25. • If we change the URLs, will we break clients?

    • If we add or remove properties, will we break clients? • If we change the input values we accept, will we break clients?
  26. • I can change URLs and nothing breaks. • I

    can add properties and nothing breaks. • If I remove properties or require new inputs, I can use content-negotiation to version the API:
 
 application/vnd.example+json; version=2 • Everybody’s happy. (Maybe?)
  27. HTTP/1.1 200 OK Date: Sat, 10 Oct 2024 17:28:45 GMT

    Accept: application/vnd.example+json; q=0.8, application/vnd.example+json; version=2; q=0.9, application/vnd.example+json; version=3 Allow: GET, PUT, PATCH, DELETE, OPTIONS, HEAD Link: </record/5s7ytJlT>; rel="self" Link: </record>; rel="collection" Link: </campaign/o0zJeEcJ>; rel="https://example.com/rel/campaign" OPTIONS /record/5s7ytJlT HTTP/1.1 Host: api.example.com Request Response
  28. Testing DSL for REST APIs • Express your API tests

    in a natural and intuitive way • Facilitates and encourages TDD and BDD for APIs • Supports validation with JSON Schema • rest-certain/rest-certain • Ports of REST Assured from Java to PHP REST Certain
  29. Thank you! Keep in touch     

     ben.ramsey.dev phpc.social/@ramsey github.com/ramsey speakerdeck.com/ramsey www.linkedin.com/in/benramsey [email protected] bram.se/phptek-rest     
  30. Resources • IANA HTTP Method Registry • IANA HTTP Field

    Name Registry • IANA Link Relations Registry • IANA Media Types Registry • RFC 9110: HTTP Semantics • RFC 5789: PATCH Method for HTTP • RFC 8288: Web Linking • Hypermedia Application Language (HAL) • Architectural Styles and the Design of Network-based Software Architectures, Roy T. Fielding
  31. Photo Credits • Clear Inner Vision. "Restful Summer." CC BY-NC-ND

    2.0. • Wouter de Bruijn. "Day 90." CC BY-NC-SA 2.0. • George Rosema. "Spider Web in morning dew." Unsplash License. • Shannon Potter. Untitled. Unsplash License. • Ibrahim Fareed. Untitled. Unsplash License. • Alice Olivier. "Popular Web 2.0 Logos." CC BY 3.0. • Carlos Torres. "From the plane." Unsplash License. • Ante Hamersmit. "Man sitting on a wooden bridge." Unsplash License. • Jacek Smoter. "Forest in central Poland." Unsplash License. • Artem Kniaz. "picturesque colorful autumn landscape….” Unsplash License. • Todd Trapani. "Up early watching the sun rise along the beach." Unsplash License. • Kaupo Kalda. "Sleepy sunset." Unsplash License. • Meina Yin. Untitled. Unsplash License. • Nathan Dumlao. Untitled. Unsplash License. • Rythik. "Silhouette." Unsplash License. • Shirley Chen. Untitled. Unsplash License. • Claudio Schwarz. Untitled. Unsplash License. • Chris Lynch. "Man sleeping on couch." Unsplash License. • Richard Bell. Untitled. Unsplash License. • Richard Beatson. Untitled. Unsplash License. • David Clode. "I am very glad that I got some photos…." Unsplash License. • Kym MacKinnon. "Ombre Sunrise Re fl ections." Unsplash License. • Jacqueline O'Gara. Untitled. Unsplash License. • Tim Johnson. Untitled. Unsplash License. • Howei Wang. Untitled. Unsplash License. • Xavier von Erlach. "The sky above the Swiss Alps after midnight." Unsplash License.