├── .gitignore ├── LICENSE ├── Procfile ├── README.md ├── composer.json ├── composer.lock ├── public ├── .htaccess └── index.php └── workshop ├── exercises ├── exercise1.md ├── exercise2.md ├── exercise3.md ├── exercise4.md └── exercise5.md └── http-toolbox.pdf /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/* 2 | 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Lorna Jane Mitchell 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: vendor/bin/heroku-php-apache2 public 2 | 3 | 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fun with HTTP 2 | 3 | This is the companion repository to my "Web Developers' HTTP Toolbox" workshop session at PHP UK 2019. The materials are not intended to stand alone and are likely to be useful only to those in the workshop. **EDIT:** I did write a follow up blog post in an attempt to make this more useful to people joining after the event 4 | 5 | ## Materials 6 | 7 | Find the slide deck and exercises in the `workshop/` folder. 8 | 9 | ## Set up the sample application 10 | 11 | This is a SlimPHP application. To set it up: 12 | 13 | * Clone the repository to your local machine 14 | * Run `composer install` in the root directory 15 | * To run locally: change to the `public/` directory and run `php -S localhost:8080`. Alternatively, there is a `Procfile` for use with Heroku if you are familiar with that platform. 16 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": { 3 | "slim/slim": "^3.11", 4 | "guzzlehttp/guzzle": "^6.3" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "4e2b898f78eaae6270e8fb9505f6a8dd", 8 | "packages": [ 9 | { 10 | "name": "container-interop/container-interop", 11 | "version": "1.2.0", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/container-interop/container-interop.git", 15 | "reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/container-interop/container-interop/zipball/79cbf1341c22ec75643d841642dd5d6acd83bdb8", 20 | "reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "psr/container": "^1.0" 25 | }, 26 | "type": "library", 27 | "autoload": { 28 | "psr-4": { 29 | "Interop\\Container\\": "src/Interop/Container/" 30 | } 31 | }, 32 | "notification-url": "https://packagist.org/downloads/", 33 | "license": [ 34 | "MIT" 35 | ], 36 | "description": "Promoting the interoperability of container objects (DIC, SL, etc.)", 37 | "homepage": "https://github.com/container-interop/container-interop", 38 | "time": "2017-02-14T19:40:03+00:00" 39 | }, 40 | { 41 | "name": "guzzlehttp/guzzle", 42 | "version": "6.3.3", 43 | "source": { 44 | "type": "git", 45 | "url": "https://github.com/guzzle/guzzle.git", 46 | "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba" 47 | }, 48 | "dist": { 49 | "type": "zip", 50 | "url": "https://api.github.com/repos/guzzle/guzzle/zipball/407b0cb880ace85c9b63c5f9551db498cb2d50ba", 51 | "reference": "407b0cb880ace85c9b63c5f9551db498cb2d50ba", 52 | "shasum": "" 53 | }, 54 | "require": { 55 | "guzzlehttp/promises": "^1.0", 56 | "guzzlehttp/psr7": "^1.4", 57 | "php": ">=5.5" 58 | }, 59 | "require-dev": { 60 | "ext-curl": "*", 61 | "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", 62 | "psr/log": "^1.0" 63 | }, 64 | "suggest": { 65 | "psr/log": "Required for using the Log middleware" 66 | }, 67 | "type": "library", 68 | "extra": { 69 | "branch-alias": { 70 | "dev-master": "6.3-dev" 71 | } 72 | }, 73 | "autoload": { 74 | "files": [ 75 | "src/functions_include.php" 76 | ], 77 | "psr-4": { 78 | "GuzzleHttp\\": "src/" 79 | } 80 | }, 81 | "notification-url": "https://packagist.org/downloads/", 82 | "license": [ 83 | "MIT" 84 | ], 85 | "authors": [ 86 | { 87 | "name": "Michael Dowling", 88 | "email": "mtdowling@gmail.com", 89 | "homepage": "https://github.com/mtdowling" 90 | } 91 | ], 92 | "description": "Guzzle is a PHP HTTP client library", 93 | "homepage": "http://guzzlephp.org/", 94 | "keywords": [ 95 | "client", 96 | "curl", 97 | "framework", 98 | "http", 99 | "http client", 100 | "rest", 101 | "web service" 102 | ], 103 | "time": "2018-04-22T15:46:56+00:00" 104 | }, 105 | { 106 | "name": "guzzlehttp/promises", 107 | "version": "v1.3.1", 108 | "source": { 109 | "type": "git", 110 | "url": "https://github.com/guzzle/promises.git", 111 | "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646" 112 | }, 113 | "dist": { 114 | "type": "zip", 115 | "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646", 116 | "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646", 117 | "shasum": "" 118 | }, 119 | "require": { 120 | "php": ">=5.5.0" 121 | }, 122 | "require-dev": { 123 | "phpunit/phpunit": "^4.0" 124 | }, 125 | "type": "library", 126 | "extra": { 127 | "branch-alias": { 128 | "dev-master": "1.4-dev" 129 | } 130 | }, 131 | "autoload": { 132 | "psr-4": { 133 | "GuzzleHttp\\Promise\\": "src/" 134 | }, 135 | "files": [ 136 | "src/functions_include.php" 137 | ] 138 | }, 139 | "notification-url": "https://packagist.org/downloads/", 140 | "license": [ 141 | "MIT" 142 | ], 143 | "authors": [ 144 | { 145 | "name": "Michael Dowling", 146 | "email": "mtdowling@gmail.com", 147 | "homepage": "https://github.com/mtdowling" 148 | } 149 | ], 150 | "description": "Guzzle promises library", 151 | "keywords": [ 152 | "promise" 153 | ], 154 | "time": "2016-12-20T10:07:11+00:00" 155 | }, 156 | { 157 | "name": "guzzlehttp/psr7", 158 | "version": "1.5.2", 159 | "source": { 160 | "type": "git", 161 | "url": "https://github.com/guzzle/psr7.git", 162 | "reference": "9f83dded91781a01c63574e387eaa769be769115" 163 | }, 164 | "dist": { 165 | "type": "zip", 166 | "url": "https://api.github.com/repos/guzzle/psr7/zipball/9f83dded91781a01c63574e387eaa769be769115", 167 | "reference": "9f83dded91781a01c63574e387eaa769be769115", 168 | "shasum": "" 169 | }, 170 | "require": { 171 | "php": ">=5.4.0", 172 | "psr/http-message": "~1.0", 173 | "ralouphie/getallheaders": "^2.0.5" 174 | }, 175 | "provide": { 176 | "psr/http-message-implementation": "1.0" 177 | }, 178 | "require-dev": { 179 | "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8" 180 | }, 181 | "type": "library", 182 | "extra": { 183 | "branch-alias": { 184 | "dev-master": "1.5-dev" 185 | } 186 | }, 187 | "autoload": { 188 | "psr-4": { 189 | "GuzzleHttp\\Psr7\\": "src/" 190 | }, 191 | "files": [ 192 | "src/functions_include.php" 193 | ] 194 | }, 195 | "notification-url": "https://packagist.org/downloads/", 196 | "license": [ 197 | "MIT" 198 | ], 199 | "authors": [ 200 | { 201 | "name": "Michael Dowling", 202 | "email": "mtdowling@gmail.com", 203 | "homepage": "https://github.com/mtdowling" 204 | }, 205 | { 206 | "name": "Tobias Schultze", 207 | "homepage": "https://github.com/Tobion" 208 | } 209 | ], 210 | "description": "PSR-7 message implementation that also provides common utility methods", 211 | "keywords": [ 212 | "http", 213 | "message", 214 | "psr-7", 215 | "request", 216 | "response", 217 | "stream", 218 | "uri", 219 | "url" 220 | ], 221 | "time": "2018-12-04T20:46:45+00:00" 222 | }, 223 | { 224 | "name": "nikic/fast-route", 225 | "version": "v1.3.0", 226 | "source": { 227 | "type": "git", 228 | "url": "https://github.com/nikic/FastRoute.git", 229 | "reference": "181d480e08d9476e61381e04a71b34dc0432e812" 230 | }, 231 | "dist": { 232 | "type": "zip", 233 | "url": "https://api.github.com/repos/nikic/FastRoute/zipball/181d480e08d9476e61381e04a71b34dc0432e812", 234 | "reference": "181d480e08d9476e61381e04a71b34dc0432e812", 235 | "shasum": "" 236 | }, 237 | "require": { 238 | "php": ">=5.4.0" 239 | }, 240 | "require-dev": { 241 | "phpunit/phpunit": "^4.8.35|~5.7" 242 | }, 243 | "type": "library", 244 | "autoload": { 245 | "psr-4": { 246 | "FastRoute\\": "src/" 247 | }, 248 | "files": [ 249 | "src/functions.php" 250 | ] 251 | }, 252 | "notification-url": "https://packagist.org/downloads/", 253 | "license": [ 254 | "BSD-3-Clause" 255 | ], 256 | "authors": [ 257 | { 258 | "name": "Nikita Popov", 259 | "email": "nikic@php.net" 260 | } 261 | ], 262 | "description": "Fast request router for PHP", 263 | "keywords": [ 264 | "router", 265 | "routing" 266 | ], 267 | "time": "2018-02-13T20:26:39+00:00" 268 | }, 269 | { 270 | "name": "pimple/pimple", 271 | "version": "v3.2.3", 272 | "source": { 273 | "type": "git", 274 | "url": "https://github.com/silexphp/Pimple.git", 275 | "reference": "9e403941ef9d65d20cba7d54e29fe906db42cf32" 276 | }, 277 | "dist": { 278 | "type": "zip", 279 | "url": "https://api.github.com/repos/silexphp/Pimple/zipball/9e403941ef9d65d20cba7d54e29fe906db42cf32", 280 | "reference": "9e403941ef9d65d20cba7d54e29fe906db42cf32", 281 | "shasum": "" 282 | }, 283 | "require": { 284 | "php": ">=5.3.0", 285 | "psr/container": "^1.0" 286 | }, 287 | "require-dev": { 288 | "symfony/phpunit-bridge": "^3.2" 289 | }, 290 | "type": "library", 291 | "extra": { 292 | "branch-alias": { 293 | "dev-master": "3.2.x-dev" 294 | } 295 | }, 296 | "autoload": { 297 | "psr-0": { 298 | "Pimple": "src/" 299 | } 300 | }, 301 | "notification-url": "https://packagist.org/downloads/", 302 | "license": [ 303 | "MIT" 304 | ], 305 | "authors": [ 306 | { 307 | "name": "Fabien Potencier", 308 | "email": "fabien@symfony.com" 309 | } 310 | ], 311 | "description": "Pimple, a simple Dependency Injection Container", 312 | "homepage": "http://pimple.sensiolabs.org", 313 | "keywords": [ 314 | "container", 315 | "dependency injection" 316 | ], 317 | "time": "2018-01-21T07:42:36+00:00" 318 | }, 319 | { 320 | "name": "psr/container", 321 | "version": "1.0.0", 322 | "source": { 323 | "type": "git", 324 | "url": "https://github.com/php-fig/container.git", 325 | "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" 326 | }, 327 | "dist": { 328 | "type": "zip", 329 | "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", 330 | "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", 331 | "shasum": "" 332 | }, 333 | "require": { 334 | "php": ">=5.3.0" 335 | }, 336 | "type": "library", 337 | "extra": { 338 | "branch-alias": { 339 | "dev-master": "1.0.x-dev" 340 | } 341 | }, 342 | "autoload": { 343 | "psr-4": { 344 | "Psr\\Container\\": "src/" 345 | } 346 | }, 347 | "notification-url": "https://packagist.org/downloads/", 348 | "license": [ 349 | "MIT" 350 | ], 351 | "authors": [ 352 | { 353 | "name": "PHP-FIG", 354 | "homepage": "http://www.php-fig.org/" 355 | } 356 | ], 357 | "description": "Common Container Interface (PHP FIG PSR-11)", 358 | "homepage": "https://github.com/php-fig/container", 359 | "keywords": [ 360 | "PSR-11", 361 | "container", 362 | "container-interface", 363 | "container-interop", 364 | "psr" 365 | ], 366 | "time": "2017-02-14T16:28:37+00:00" 367 | }, 368 | { 369 | "name": "psr/http-message", 370 | "version": "1.0.1", 371 | "source": { 372 | "type": "git", 373 | "url": "https://github.com/php-fig/http-message.git", 374 | "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" 375 | }, 376 | "dist": { 377 | "type": "zip", 378 | "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", 379 | "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", 380 | "shasum": "" 381 | }, 382 | "require": { 383 | "php": ">=5.3.0" 384 | }, 385 | "type": "library", 386 | "extra": { 387 | "branch-alias": { 388 | "dev-master": "1.0.x-dev" 389 | } 390 | }, 391 | "autoload": { 392 | "psr-4": { 393 | "Psr\\Http\\Message\\": "src/" 394 | } 395 | }, 396 | "notification-url": "https://packagist.org/downloads/", 397 | "license": [ 398 | "MIT" 399 | ], 400 | "authors": [ 401 | { 402 | "name": "PHP-FIG", 403 | "homepage": "http://www.php-fig.org/" 404 | } 405 | ], 406 | "description": "Common interface for HTTP messages", 407 | "homepage": "https://github.com/php-fig/http-message", 408 | "keywords": [ 409 | "http", 410 | "http-message", 411 | "psr", 412 | "psr-7", 413 | "request", 414 | "response" 415 | ], 416 | "time": "2016-08-06T14:39:51+00:00" 417 | }, 418 | { 419 | "name": "ralouphie/getallheaders", 420 | "version": "2.0.5", 421 | "source": { 422 | "type": "git", 423 | "url": "https://github.com/ralouphie/getallheaders.git", 424 | "reference": "5601c8a83fbba7ef674a7369456d12f1e0d0eafa" 425 | }, 426 | "dist": { 427 | "type": "zip", 428 | "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/5601c8a83fbba7ef674a7369456d12f1e0d0eafa", 429 | "reference": "5601c8a83fbba7ef674a7369456d12f1e0d0eafa", 430 | "shasum": "" 431 | }, 432 | "require": { 433 | "php": ">=5.3" 434 | }, 435 | "require-dev": { 436 | "phpunit/phpunit": "~3.7.0", 437 | "satooshi/php-coveralls": ">=1.0" 438 | }, 439 | "type": "library", 440 | "autoload": { 441 | "files": [ 442 | "src/getallheaders.php" 443 | ] 444 | }, 445 | "notification-url": "https://packagist.org/downloads/", 446 | "license": [ 447 | "MIT" 448 | ], 449 | "authors": [ 450 | { 451 | "name": "Ralph Khattar", 452 | "email": "ralph.khattar@gmail.com" 453 | } 454 | ], 455 | "description": "A polyfill for getallheaders.", 456 | "time": "2016-02-11T07:05:27+00:00" 457 | }, 458 | { 459 | "name": "slim/slim", 460 | "version": "3.11.0", 461 | "source": { 462 | "type": "git", 463 | "url": "https://github.com/slimphp/Slim.git", 464 | "reference": "d378e70431e78ee92ee32ddde61ecc72edf5dc0a" 465 | }, 466 | "dist": { 467 | "type": "zip", 468 | "url": "https://api.github.com/repos/slimphp/Slim/zipball/d378e70431e78ee92ee32ddde61ecc72edf5dc0a", 469 | "reference": "d378e70431e78ee92ee32ddde61ecc72edf5dc0a", 470 | "shasum": "" 471 | }, 472 | "require": { 473 | "container-interop/container-interop": "^1.2", 474 | "nikic/fast-route": "^1.0", 475 | "php": ">=5.5.0", 476 | "pimple/pimple": "^3.0", 477 | "psr/container": "^1.0", 478 | "psr/http-message": "^1.0" 479 | }, 480 | "provide": { 481 | "psr/http-message-implementation": "1.0" 482 | }, 483 | "require-dev": { 484 | "phpunit/phpunit": "^4.0", 485 | "squizlabs/php_codesniffer": "^2.5" 486 | }, 487 | "type": "library", 488 | "autoload": { 489 | "psr-4": { 490 | "Slim\\": "Slim" 491 | } 492 | }, 493 | "notification-url": "https://packagist.org/downloads/", 494 | "license": [ 495 | "MIT" 496 | ], 497 | "authors": [ 498 | { 499 | "name": "Rob Allen", 500 | "email": "rob@akrabat.com", 501 | "homepage": "http://akrabat.com" 502 | }, 503 | { 504 | "name": "Josh Lockhart", 505 | "email": "hello@joshlockhart.com", 506 | "homepage": "https://joshlockhart.com" 507 | }, 508 | { 509 | "name": "Gabriel Manricks", 510 | "email": "gmanricks@me.com", 511 | "homepage": "http://gabrielmanricks.com" 512 | }, 513 | { 514 | "name": "Andrew Smith", 515 | "email": "a.smith@silentworks.co.uk", 516 | "homepage": "http://silentworks.co.uk" 517 | } 518 | ], 519 | "description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs", 520 | "homepage": "https://slimframework.com", 521 | "keywords": [ 522 | "api", 523 | "framework", 524 | "micro", 525 | "router" 526 | ], 527 | "time": "2018-09-16T10:54:21+00:00" 528 | } 529 | ], 530 | "packages-dev": [], 531 | "aliases": [], 532 | "minimum-stability": "stable", 533 | "stability-flags": [], 534 | "prefer-stable": false, 535 | "prefer-lowest": false, 536 | "platform": [], 537 | "platform-dev": [] 538 | } 539 | -------------------------------------------------------------------------------- /public/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | RewriteEngine On 3 | RewriteBase / 4 | RewriteRule ^index\.php$ - [L] 5 | RewriteCond %{REQUEST_FILENAME} !-f 6 | RewriteCond %{REQUEST_FILENAME} !-d 7 | RewriteRule . /index.php [L] 8 | 9 | -------------------------------------------------------------------------------- /public/index.php: -------------------------------------------------------------------------------- 1 | map(['GET', 'POST'], '/check', function ($request, $response, $args) { 9 | // query parameters 10 | $get_params = $request->getQueryParams(); 11 | // body params, using Content-Type to figure out if it's form or JSON 12 | $post_params = $request->getParsedBody(); 13 | 14 | // accept header sets response format 15 | $accept = $request->getHeader('Accept')[0]; 16 | 17 | // build the array of parameters and sources 18 | $all_params = []; 19 | 20 | if ($get_params) { 21 | $all_params['GET'] = $get_params; 22 | } 23 | 24 | if ($post_params) { 25 | $all_params['POST'] = $post_params; 26 | } 27 | 28 | switch ($accept) { 29 | case 'application/json': 30 | return $response->withJson($all_params); 31 | break; 32 | default: // plain text 33 | return $response->getBody()->write(print_r($all_params, true)); 34 | } 35 | 36 | }); 37 | 38 | $app->get('/', function ($request, $response, $args) { 39 | return $response->getBody()->write("Hello World"); 40 | }); 41 | 42 | $app->get('/talks', function ($request, $response, $args) { 43 | $client = new \GuzzleHttp\Client(); 44 | 45 | $response = $client->request("GET", "http://api.joind.in"); 46 | error_log($response->getBody()); 47 | 48 | return $response->getBody()->write("OK"); 49 | }); 50 | 51 | $app->run(); 52 | -------------------------------------------------------------------------------- /workshop/exercises/exercise1.md: -------------------------------------------------------------------------------- 1 | # Exercise 1: Let's begin 2 | 3 | You will need: 4 | 5 | * any HTTP client: your browser, Postman, curl or something else (or all of these!) 6 | * a PHP installation (can be Heroku or similar) 7 | 8 | ## Set up Sample App 9 | 10 | Clone the repo at https://github.com/lornajane/fun-with-http and get the app running (instructions in the `README`). 11 | 12 | ## Use HTTP Clients 13 | 14 | Try different clients and hit the root URL to get a "Hello World" response. 15 | 16 | ## Appendix A: clickable links to HTTP clients 17 | 18 | * Curl https://curl.haxx.se/ 19 | * Postman https://www.getpostman.com/ 20 | * HTTPie https://httpie.org/ 21 | * http-console https://github.com/cloudhead/http-console 22 | 23 | -------------------------------------------------------------------------------- /workshop/exercises/exercise2.md: -------------------------------------------------------------------------------- 1 | # Exercise 2: Working with data 2 | 3 | ## Sending data 4 | 5 | Try sending some `GET` and `POST` requests to the `/check` endpoint. It should echo the data back to you, so take a look and make sure it understood you. 6 | 7 | You can also send data in JSON format - make sure your client also sends the `Content-Type: application/json` header. 8 | 9 | ## Receiving data 10 | 11 | How about receiving that data in a different format? Send `Accept: application/json` as a header and inspect the response using appropriate tools to get decoded JSON values. 12 | 13 | ## Appendix A: JSON-wrangling tools for command line 14 | 15 | * `jq` https://stedolan.github.io/jq/ 16 | * `fx` https://github.com/antonmedv/fx 17 | -------------------------------------------------------------------------------- /workshop/exercises/exercise3.md: -------------------------------------------------------------------------------- 1 | # Exercise 3: Calling another API 2 | 3 | From our PHP application, we get data from another API (in this case https://api.joind.in). 4 | 5 | ## Testing API calls 6 | 7 | Set up a local RequestBin and send some requests to it from your HTTP client. 8 | 9 | ## Request external data 10 | 11 | There is an incomplete endpoint in `index.php` called `/talks`. Work out how to make the correct request to the API to get all the talks for this event in JSON format. As you work on this task, remember that you can change the destination URL to point to the RequestBin and inspect that you are sending the request you expected. 12 | 13 | ## Appendix A: Resources 14 | 15 | My fork of Requestbin has some patches that should allow it to run on Heroku. https://github.com/lornajane/requestbin 16 | 17 | Joind.in API docs: http://docs.joind.in/joindin-api/ , you don't need to authenticate to retrieve this public data. Note that the API also has an HTML output handler so you can click around in your browser to explore. 18 | -------------------------------------------------------------------------------- /workshop/exercises/exercise4.md: -------------------------------------------------------------------------------- 1 | # Exercise 4: Local Development Shared Publicly 2 | 3 | ## Install ngrok 4 | 5 | Set up ngrok on your local platform 6 | 7 | ## Try the app from another device 8 | 9 | Swap URLs with the person next to you or try accessing the project from your phone. Edit the application code and observe the changes on the other device. 10 | 11 | ## Retry requests 12 | 13 | Take a look at the ngrok dashboard and replay a request, look at the response. Edit the application code so the output will be different, and replay again. Repeat this as much as you like! 14 | -------------------------------------------------------------------------------- /workshop/exercises/exercise5.md: -------------------------------------------------------------------------------- 1 | # Exercise 5: Local Proxy Tools 2 | 3 | ## Proxy of your choice 4 | 5 | It's the last exercise, pick one of the proxy tools, get it working and use it to inspect traffic (ngrok gives us some of this functionality). Investigate how you would use TLS with this tool. 6 | 7 | ## Appendix A: Links to proxy tools 8 | 9 | * Charles Proxy https://www.charlesproxy.com/ 10 | * WireShark https://www.wireshark.org/ 11 | * Mitmproxy https://mitmproxy.org/ 12 | -------------------------------------------------------------------------------- /workshop/http-toolbox.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lornajane/fun-with-http/5a13c48cff8b87b6c22460e3587f0317d4b8d2b5/workshop/http-toolbox.pdf --------------------------------------------------------------------------------