├── .gitignore ├── 03-jwt ├── gateway │ ├── Dockerfile │ └── krakend.json ├── monolito │ ├── utils.php │ ├── auth │ │ ├── AuthHelper.php │ │ └── SessionAuth.php │ ├── controller │ │ ├── Controller.php │ │ ├── LogoutController.php │ │ ├── JWKController.php │ │ ├── LoginPostController.php │ │ ├── PathsGetController.php │ │ ├── AuthorsGetController.php │ │ └── CoursesGetController.php │ ├── middleware │ │ └── AuthMiddleware.php │ └── index.php ├── docker-compose.yml └── example-curls.sh ├── README.md ├── 01-monolith ├── docker-compose.yml ├── utils.php ├── auth │ ├── AuthHelper.php │ └── SessionAuth.php ├── controller │ ├── Controller.php │ ├── LogoutController.php │ ├── LoginPostController.php │ └── CoursesGetController.php ├── example-curls.sh ├── middleware │ └── AuthMiddleware.php ├── index.php └── README.md ├── 04-auth-microservice ├── identity │ ├── utils.php │ ├── auth │ │ ├── AuthHelper.php │ │ └── SessionAuth.php │ ├── controller │ │ ├── Controller.php │ │ ├── LogoutController.php │ │ ├── JWKController.php │ │ └── LoginPostController.php │ └── index.php ├── monolito │ ├── auth │ │ ├── AuthHelper.php │ │ └── SessionAuth.php │ ├── controller │ │ ├── Controller.php │ │ ├── PathsGetController.php │ │ ├── AuthorsGetController.php │ │ └── CoursesGetController.php │ ├── middleware │ │ └── AuthMiddleware.php │ └── index.php ├── docker-compose.yml ├── example-curls.sh └── gateway │ └── krakend.json ├── 05-requests-and-responses ├── 05.2-serializing │ └── monolito │ │ ├── auth │ │ ├── AuthHelper.php │ │ └── SessionAuth.php │ │ ├── middleware │ │ └── AuthMiddleware.php │ │ ├── controller │ │ ├── RelatedCoursesGetController.php │ │ ├── Controller.php │ │ ├── PathsGetController.php │ │ ├── AuthorsGetController.php │ │ └── CoursesGetController.php │ │ └── index.php ├── 05.3-standarization │ └── monolito │ │ ├── auth │ │ ├── AuthHelper.php │ │ └── SessionAuth.php │ │ ├── middleware │ │ └── AuthMiddleware.php │ │ ├── controller │ │ ├── RelatedCoursesGetController.php │ │ ├── Controller.php │ │ ├── PathsGetController.php │ │ ├── AuthorsGetController.php │ │ └── CoursesGetController.php │ │ └── index.php └── 05.1-splitting-in-multiples-endpoints │ └── monolito │ ├── auth │ ├── AuthHelper.php │ └── SessionAuth.php │ ├── middleware │ └── AuthMiddleware.php │ ├── controller │ ├── Controller.php │ ├── PathsGetController.php │ ├── AuthorsGetController.php │ └── CoursesGetController.php │ └── index.php ├── 06-migrating-product-page ├── 06.1-mocking-response │ └── monolito │ │ ├── auth │ │ ├── AuthHelper.php │ │ └── SessionAuth.php │ │ ├── middleware │ │ └── AuthMiddleware.php │ │ ├── controller │ │ ├── RelatedCoursesGetController.php │ │ ├── Controller.php │ │ ├── PathsGetController.php │ │ ├── AuthorsGetController.php │ │ └── CoursesGetController.php │ │ ├── top-courses.json │ │ └── index.php └── 06.2-order-petitions │ └── monolito │ ├── auth │ ├── AuthHelper.php │ └── SessionAuth.php │ ├── middleware │ └── AuthMiddleware.php │ ├── controller │ ├── RelatedCoursesGetController.php │ ├── PricingPlanGetController.php │ ├── Controller.php │ ├── PathsGetController.php │ ├── AuthorsGetController.php │ └── CoursesGetController.php │ ├── top-courses.json │ └── index.php └── 02-proxy ├── docker-compose.yml ├── example-curls.sh └── krakend.json /.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /03-jwt/gateway/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM devopsfaith/krakend 2 | 3 | COPY krakend.json /etc/krakend/krakend.json 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # De monolito a microservicios con API Gateway 2 | Repositorio con snippets de código utilizados en el curso **De monolito a microservicios con API Gateway** en la plataforma [CodelyTV](https://codely.tv/pro/cursos). -------------------------------------------------------------------------------- /01-monolith/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | monolith: 4 | image: php:7 5 | command: ["php", "-S", "0.0.0.0:8081", "/app/index.php"] 6 | ports: 7 | - 8081:8081 8 | volumes: 9 | - ./:/app -------------------------------------------------------------------------------- /01-monolith/utils.php: -------------------------------------------------------------------------------- 1 | [ 5 | 'pwd' => 'tupu', 6 | 'roles' => ['user', 'admin'] 7 | ], 8 | 'dani' => [ 9 | 'pwd' => 'supu', 10 | 'roles' => ['user'] 11 | ] 12 | ]; -------------------------------------------------------------------------------- /03-jwt/monolito/utils.php: -------------------------------------------------------------------------------- 1 | [ 5 | 'pwd' => 'tupu', 6 | 'roles' => ['user', 'admin'], 7 | ], 8 | 'dani' => [ 9 | 'pwd' => 'supu', 10 | 'roles' => ['user'], 11 | ] 12 | ]; -------------------------------------------------------------------------------- /04-auth-microservice/identity/utils.php: -------------------------------------------------------------------------------- 1 | [ 5 | 'pwd' => 'tupu', 6 | 'roles' => ['user', 'admin'], 7 | ], 8 | 'dani' => [ 9 | 'pwd' => 'supu', 10 | 'roles' => ['user'], 11 | ] 12 | ]; -------------------------------------------------------------------------------- /01-monolith/auth/AuthHelper.php: -------------------------------------------------------------------------------- 1 | helper = $helper; 12 | } 13 | 14 | public function handle(array $request): string 15 | { 16 | if (!$this->helper->isLogged()) { 17 | header('HTTP/1.0 401 Unauthorized'); 18 | echo 'Invalid credentials!'; 19 | exit; 20 | } 21 | 22 | $this->helper->logout(); 23 | 24 | return 'Bye!'; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /03-jwt/monolito/controller/LogoutController.php: -------------------------------------------------------------------------------- 1 | helper = $helper; 12 | } 13 | 14 | public function handle(array $request): string 15 | { 16 | if (!$this->helper->isLogged()) { 17 | header('HTTP/1.0 401 Unauthorized'); 18 | echo 'Invalid credentials!'; 19 | exit; 20 | } 21 | 22 | $this->helper->logout(); 23 | 24 | return 'Bye!'; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /04-auth-microservice/identity/controller/LogoutController.php: -------------------------------------------------------------------------------- 1 | helper = $helper; 12 | } 13 | 14 | public function handle(array $request): string 15 | { 16 | if (!$this->helper->isLogged()) { 17 | header('HTTP/1.0 401 Unauthorized'); 18 | echo 'Invalid credentials!'; 19 | exit; 20 | } 21 | 22 | $this->helper->logout(); 23 | 24 | return 'Bye!'; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /03-jwt/monolito/controller/JWKController.php: -------------------------------------------------------------------------------- 1 | jsonResponse( 10 | [ 11 | "keys" => [ 12 | [ 13 | "kty" => "oct", 14 | "alg" => "A128KW", 15 | "k" => "GawgguFyGrWKav7AX4VKUg", 16 | "kid" => "sim1" 17 | ], 18 | [ 19 | "kty" => "oct", 20 | "k" => "AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow", 21 | "kid" => "sim2", 22 | "alg" => "HS256" 23 | ] 24 | ] 25 | ] 26 | ); 27 | } 28 | } -------------------------------------------------------------------------------- /04-auth-microservice/identity/controller/JWKController.php: -------------------------------------------------------------------------------- 1 | jsonResponse( 10 | [ 11 | "keys" => [ 12 | [ 13 | "kty" => "oct", 14 | "alg" => "A128KW", 15 | "k" => "GawgguFyGrWKav7AX4VKUg", 16 | "kid" => "sim1" 17 | ], 18 | [ 19 | "kty" => "oct", 20 | "k" => "AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow", 21 | "kid" => "sim2", 22 | "alg" => "HS256" 23 | ] 24 | ] 25 | ] 26 | ); 27 | } 28 | } -------------------------------------------------------------------------------- /01-monolith/middleware/AuthMiddleware.php: -------------------------------------------------------------------------------- 1 | controller = $controller; 13 | $this->helper = $helper; 14 | } 15 | 16 | public function handle(array $request): string 17 | { 18 | if (!$this->helper->isLogged()) { 19 | header('HTTP/1.0 401 Unauthorized'); 20 | echo 'Unauthorized!!!'; 21 | exit; 22 | } 23 | 24 | return $this->controller->handle($request); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /03-jwt/monolito/middleware/AuthMiddleware.php: -------------------------------------------------------------------------------- 1 | controller = $controller; 13 | $this->helper = $helper; 14 | } 15 | 16 | public function handle(array $request): string 17 | { 18 | if (!$this->helper->isLogged()) { 19 | header('HTTP/1.0 401 Unauthorized'); 20 | echo 'Unauthorized!!!'; 21 | exit; 22 | } 23 | 24 | return $this->controller->handle($request); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /04-auth-microservice/monolito/middleware/AuthMiddleware.php: -------------------------------------------------------------------------------- 1 | controller = $controller; 13 | $this->helper = $helper; 14 | } 15 | 16 | public function handle(array $request): string 17 | { 18 | if (!$this->helper->isLogged()) { 19 | header('HTTP/1.0 401 Unauthorized'); 20 | echo 'Unauthorized!!!'; 21 | exit; 22 | } 23 | 24 | return $this->controller->handle($request); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /02-proxy/example-curls.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Notice how all the traffic is now through KrakenD (8080) instead of the backend (8081) 3 | 4 | # Login and capture of cookie value from the `Set-Cookie`header: 5 | echo "Logging in..." 6 | COOKIE=$(curl -s -iXPOST -F'username=dani' -F'pwd=supu' http://127.0.0.1:8080/login | grep Set-Cookie | cut -d' ' -f2-) 7 | 8 | # Inject the cookie in the following responses: 9 | echo "Retrieving protected endpoint" 10 | curl -iH"Cookie: $COOKIE" "http://127.0.0.1:8080/courses?course_id=77070" 11 | 12 | # Bye! 13 | echo "Logging out" 14 | curl -iH"Cookie: $COOKIE" http://127.0.0.1:8080/logout 15 | 16 | curl -iH"Cookie: $(printf $COOKIE)" "http://127.0.0.1:8080/courses?course_id=77070" -------------------------------------------------------------------------------- /05-requests-and-responses/05.2-serializing/monolito/middleware/AuthMiddleware.php: -------------------------------------------------------------------------------- 1 | controller = $controller; 13 | $this->helper = $helper; 14 | } 15 | 16 | public function handle(array $request): string 17 | { 18 | if (!$this->helper->isLogged()) { 19 | header('HTTP/1.0 401 Unauthorized'); 20 | echo 'Unauthorized!!!'; 21 | exit; 22 | } 23 | 24 | return $this->controller->handle($request); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /05-requests-and-responses/05.3-standarization/monolito/middleware/AuthMiddleware.php: -------------------------------------------------------------------------------- 1 | controller = $controller; 13 | $this->helper = $helper; 14 | } 15 | 16 | public function handle(array $request): string 17 | { 18 | if (!$this->helper->isLogged()) { 19 | header('HTTP/1.0 401 Unauthorized'); 20 | echo 'Unauthorized!!!'; 21 | exit; 22 | } 23 | 24 | return $this->controller->handle($request); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /06-migrating-product-page/06.1-mocking-response/monolito/middleware/AuthMiddleware.php: -------------------------------------------------------------------------------- 1 | controller = $controller; 13 | $this->helper = $helper; 14 | } 15 | 16 | public function handle(array $request): string 17 | { 18 | if (!$this->helper->isLogged()) { 19 | header('HTTP/1.0 401 Unauthorized'); 20 | echo 'Unauthorized!!!'; 21 | exit; 22 | } 23 | 24 | return $this->controller->handle($request); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /06-migrating-product-page/06.2-order-petitions/monolito/middleware/AuthMiddleware.php: -------------------------------------------------------------------------------- 1 | controller = $controller; 13 | $this->helper = $helper; 14 | } 15 | 16 | public function handle(array $request): string 17 | { 18 | if (!$this->helper->isLogged()) { 19 | header('HTTP/1.0 401 Unauthorized'); 20 | echo 'Unauthorized!!!'; 21 | exit; 22 | } 23 | 24 | return $this->controller->handle($request); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /04-auth-microservice/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | monolith: 4 | image: php:7 5 | command: ["php", "-S", "0.0.0.0:8081", "/app/index.php"] 6 | # Port exposed for testing, no need to be public as interaction goes through KrakenD: 7 | ports: 8 | - 8081:8081 9 | volumes: 10 | - ./monolito/:/app 11 | identity: 12 | image: php:7 13 | command: ["php", "-S", "0.0.0.0:8082", "/app/index.php"] 14 | # Port exposed for testing, no need to be public as interaction goes through KrakenD: 15 | ports: 16 | - 8082:8082 17 | volumes: 18 | - ./identity/:/app 19 | krakend: 20 | image: devopsfaith/krakend 21 | volumes: 22 | - ./gateway:/etc/krakend 23 | ports: 24 | - 8080:8080 -------------------------------------------------------------------------------- /05-requests-and-responses/05.1-splitting-in-multiples-endpoints/monolito/middleware/AuthMiddleware.php: -------------------------------------------------------------------------------- 1 | controller = $controller; 13 | $this->helper = $helper; 14 | } 15 | 16 | public function handle(array $request): string 17 | { 18 | if (!$this->helper->isLogged()) { 19 | header('HTTP/1.0 401 Unauthorized'); 20 | echo 'Unauthorized!!!'; 21 | exit; 22 | } 23 | 24 | return $this->controller->handle($request); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /03-jwt/example-curls.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # The login endpoint has been modified in the monolith to return an access token instead. 3 | # KrakenD signs this token. 4 | 5 | # Login and capture of the JWT token: 6 | echo "Logging in..." 7 | TOKEN=$(curl -s -XPOST -F'username=dani' -F'pwd=supu' http://127.0.0.1:8080/login | jq -r '.access_token' ) 8 | 9 | # Inject the token in the following responses: 10 | echo "Retrieving course 77070" 11 | curl -iH"Authorization: bearer $TOKEN" "http://127.0.0.1:8080/courses?course_id=77070" 12 | 13 | echo "Retrieving paths" 14 | curl -iH"Authorization: bearer $TOKEN" "http://127.0.0.1:8080/paths" 15 | 16 | echo "Retrieving paths" 17 | curl -iH"Authorization: bearer $TOKEN" "http://127.0.0.1:8080/authors" 18 | 19 | # Bye! 20 | echo "Logging out" 21 | -------------------------------------------------------------------------------- /01-monolith/controller/LoginPostController.php: -------------------------------------------------------------------------------- 1 | helper = $helper; 12 | } 13 | 14 | public function handle(array $request): string 15 | { 16 | if (!$this->helper->isLogged()) { 17 | $userData = $this->helper->login($request); 18 | if (sizeof($userData) === 0) { 19 | header('HTTP/1.0 401 Unauthorized'); 20 | echo 'Invalid credentials!'; 21 | exit; 22 | } 23 | $this->helper->startUserSession($userData); 24 | } 25 | 26 | return 'Logged in!'; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /04-auth-microservice/monolito/auth/SessionAuth.php: -------------------------------------------------------------------------------- 1 | [66748, 90916], 9 | 66748 => [90916, 77070, 87157], 10 | 90916 => [66748, 66748], 11 | 87157 => [77070, 66748, 90916], 12 | ]; 13 | 14 | public function handle(array $request): string 15 | { 16 | if (!isset($request['course_id'])) { 17 | $this->notFoundResponse('You should pass the course_id to found the relates'); 18 | } 19 | 20 | $courseId = $request['course_id']; 21 | 22 | return isset(self::RELATED_COURSES[$courseId]) 23 | ? $this->xmlResponse(self::RELATED_COURSES[$courseId]) 24 | : $this->notFoundResponse("The course `$courseId` doesn't exist or has no relates"); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /05-requests-and-responses/05.3-standarization/monolito/controller/RelatedCoursesGetController.php: -------------------------------------------------------------------------------- 1 | [66748, 90916], 9 | 66748 => [90916, 77070, 87157], 10 | 90916 => [66748, 66748], 11 | 87157 => [77070, 66748, 90916], 12 | ]; 13 | 14 | public function handle(array $request): string 15 | { 16 | if (!isset($request['course_id'])) { 17 | $this->notFoundResponse('You should pass the course_id to found the relates'); 18 | } 19 | 20 | $courseId = $request['course_id']; 21 | 22 | return isset(self::RELATED_COURSES[$courseId]) 23 | ? $this->xmlResponse(self::RELATED_COURSES[$courseId]) 24 | : $this->notFoundResponse("The course `$courseId` doesn't exist or has no relates"); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /06-migrating-product-page/06.1-mocking-response/monolito/controller/RelatedCoursesGetController.php: -------------------------------------------------------------------------------- 1 | [66748, 90916], 9 | 66748 => [90916, 77070, 87157], 10 | 90916 => [66748, 66748], 11 | 87157 => [77070, 66748, 90916], 12 | ]; 13 | 14 | public function handle(array $request): string 15 | { 16 | if (!isset($request['course_id'])) { 17 | $this->notFoundResponse('You should pass the course_id to found the relates'); 18 | } 19 | 20 | $courseId = $request['course_id']; 21 | 22 | return isset(self::RELATED_COURSES[$courseId]) 23 | ? $this->xmlResponse(self::RELATED_COURSES[$courseId]) 24 | : $this->notFoundResponse("The course `$courseId` doesn't exist or has no relates"); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /06-migrating-product-page/06.2-order-petitions/monolito/controller/RelatedCoursesGetController.php: -------------------------------------------------------------------------------- 1 | [66748, 90916], 9 | 66748 => [90916, 77070, 87157], 10 | 90916 => [66748, 66748], 11 | 87157 => [77070, 66748, 90916], 12 | ]; 13 | 14 | public function handle(array $request): string 15 | { 16 | if (!isset($request['course_id'])) { 17 | $this->notFoundResponse('You should pass the course_id to found the relates'); 18 | } 19 | 20 | $courseId = $request['course_id']; 21 | 22 | return isset(self::RELATED_COURSES[$courseId]) 23 | ? $this->xmlResponse(self::RELATED_COURSES[$courseId]) 24 | : $this->notFoundResponse("The course `$courseId` doesn't exist or has no relates"); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /03-jwt/monolito/controller/LoginPostController.php: -------------------------------------------------------------------------------- 1 | helper = $helper; 12 | } 13 | 14 | public function handle(array $request): string 15 | { 16 | $userData = $this->helper->login($request); 17 | if (sizeof($userData) === 0) { 18 | header('HTTP/1.0 401 Unauthorized'); 19 | echo 'Invalid credentials!'; 20 | exit; 21 | } 22 | 23 | return $this->jsonResponse( 24 | [ 25 | "access_token" => [ 26 | "aud" => "http://api.company.com", 27 | "iss" => "http://monoli.th", 28 | "sub" => $request['username'], 29 | "jti" => uniqid('', true), 30 | "roles" => $userData['roles'], 31 | "exp" => time() + 1800, // 30 minutes 32 | "other_data" => $userData['other'] 33 | ] 34 | ] 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /04-auth-microservice/identity/controller/LoginPostController.php: -------------------------------------------------------------------------------- 1 | helper = $helper; 12 | } 13 | 14 | public function handle(array $request): string 15 | { 16 | $userData = $this->helper->login($request); 17 | if (sizeof($userData) === 0) { 18 | header('HTTP/1.0 401 Unauthorized'); 19 | echo 'Invalid credentials!'; 20 | exit; 21 | } 22 | 23 | return $this->jsonResponse( 24 | [ 25 | "access_token" => [ 26 | "aud" => "http://api.company.com", 27 | "iss" => "http://monoli.th", 28 | "sub" => $request['username'], 29 | "jti" => uniqid('', true), 30 | "roles" => $userData['roles'], 31 | "exp" => time() + 1800, // 30 minutes 32 | "other_data" => $userData['other'] 33 | ] 34 | ] 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /05-requests-and-responses/05.1-splitting-in-multiples-endpoints/monolito/controller/Controller.php: -------------------------------------------------------------------------------- 1 | extractResourceId($request); 26 | } 27 | 28 | protected function resourceId(array $request): string 29 | { 30 | return $this->extractResourceId($request); 31 | } 32 | 33 | private function extractResourceId(array $request): ?string 34 | { 35 | $urlParts = explode('/', $request['REQUEST_URL']); 36 | 37 | if (count($urlParts) > 2) { 38 | return $urlParts[2]; 39 | } 40 | 41 | return null; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /04-auth-microservice/identity/index.php: -------------------------------------------------------------------------------- 1 | handle($_REQUEST); 20 | break; 21 | default: 22 | $response = "The POST `$url` doesn't exist!"; 23 | break; 24 | } 25 | } else { 26 | switch ($url) { 27 | case '/logout': 28 | $response = (new LogoutController(new SessionAuth($usersPass)))->handle($_REQUEST); 29 | 30 | break; 31 | case '/jwk': 32 | $response = (new JWKController())->handle($_REQUEST); 33 | 34 | break; 35 | default: 36 | $response = "The GET `$url` doesn't exist!"; 37 | break; 38 | } 39 | } 40 | 41 | echo $response; 42 | -------------------------------------------------------------------------------- /06-migrating-product-page/06.2-order-petitions/monolito/controller/PricingPlanGetController.php: -------------------------------------------------------------------------------- 1 | [ 9 | 'id' => '4c5be45d-799b-49c5-93bc-859a832a2a65', 10 | 'name' => 'Standard', 11 | 'monthly_cost_in_eur' => 29, 12 | ], 13 | 'f1f62b61-e123-434f-99ff-4c64d7f34f3b' => [ 14 | 'id' => 'f1f62b61-e123-434f-99ff-4c64d7f34f3b', 15 | 'name' => 'Premium', 16 | 'monthly_cost_in_eur' => 49, 17 | ], 18 | ]; 19 | 20 | public function handle(array $request): string 21 | { 22 | if (!$this->hasResourceId($request)) { 23 | $this->notFoundResponse('You should pass the pricing plan id'); 24 | } 25 | 26 | $pricingPlanId = $this->resourceId($request); 27 | 28 | return isset(self::ALL_PRICING_PLANS[$pricingPlanId]) 29 | ? $this->jsonResponse(self::ALL_PRICING_PLANS[$pricingPlanId]) 30 | : $this->notFoundResponse("The pricing plan `$pricingPlanId` doesn't exist"); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /04-auth-microservice/monolito/index.php: -------------------------------------------------------------------------------- 1 | handle($_REQUEST); 24 | 25 | break; 26 | case '/courses': 27 | $response = (new AuthMiddleware(new CoursesGetController(), new SessionAuth()))->handle($_REQUEST); 28 | 29 | break; 30 | case '/paths': 31 | $response = (new AuthMiddleware(new PathsGetController(), new SessionAuth()))->handle($_REQUEST); 32 | 33 | break; 34 | default: 35 | $response = "The GET `$url` doesn't exist!"; 36 | break; 37 | } 38 | } 39 | 40 | echo $response; 41 | -------------------------------------------------------------------------------- /05-requests-and-responses/05.2-serializing/monolito/controller/Controller.php: -------------------------------------------------------------------------------- 1 | extractResourceId($request); 33 | } 34 | 35 | protected function resourceId(array $request): string 36 | { 37 | return $this->extractResourceId($request); 38 | } 39 | 40 | private function extractResourceId(array $request): ?string 41 | { 42 | $urlParts = explode('/', $request['REQUEST_URL']); 43 | 44 | if (count($urlParts) > 2) { 45 | return $urlParts[2]; 46 | } 47 | 48 | return null; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /05-requests-and-responses/05.3-standarization/monolito/controller/Controller.php: -------------------------------------------------------------------------------- 1 | extractResourceId($request); 33 | } 34 | 35 | protected function resourceId(array $request): string 36 | { 37 | return $this->extractResourceId($request); 38 | } 39 | 40 | private function extractResourceId(array $request): ?string 41 | { 42 | $urlParts = explode('/', $request['REQUEST_URL']); 43 | 44 | if (count($urlParts) > 2) { 45 | return $urlParts[2]; 46 | } 47 | 48 | return null; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /06-migrating-product-page/06.2-order-petitions/monolito/controller/Controller.php: -------------------------------------------------------------------------------- 1 | extractResourceId($request); 33 | } 34 | 35 | protected function resourceId(array $request): string 36 | { 37 | return $this->extractResourceId($request); 38 | } 39 | 40 | private function extractResourceId(array $request): ?string 41 | { 42 | $urlParts = explode('/', $request['REQUEST_URL']); 43 | 44 | if (count($urlParts) > 2) { 45 | return $urlParts[2]; 46 | } 47 | 48 | return null; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /06-migrating-product-page/06.1-mocking-response/monolito/controller/Controller.php: -------------------------------------------------------------------------------- 1 | extractResourceId($request); 33 | } 34 | 35 | protected function resourceId(array $request): string 36 | { 37 | return $this->extractResourceId($request); 38 | } 39 | 40 | private function extractResourceId(array $request): ?string 41 | { 42 | $urlParts = explode('/', $request['REQUEST_URL']); 43 | 44 | if (count($urlParts) > 2) { 45 | return $urlParts[2]; 46 | } 47 | 48 | return null; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /02-proxy/krakend.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "timeout": "3000ms", 4 | "port": 8080, 5 | "cache_ttl": "300s", 6 | "host": [ 7 | "http://monolith:8081" 8 | ], 9 | "endpoints": [ 10 | { 11 | "endpoint": "/authors", 12 | "headers_to_pass": ["*"], 13 | "output_encoding": "no-op", 14 | "backend": [ 15 | { 16 | "url_pattern": "/authors", 17 | "encoding": "no-op" 18 | } 19 | ] 20 | }, 21 | { 22 | "endpoint": "/courses", 23 | "headers_to_pass": ["*"], 24 | "output_encoding": "no-op", 25 | "backend": [ 26 | { 27 | "url_pattern": "/courses", 28 | "encoding": "no-op" 29 | } 30 | ] 31 | }, 32 | { 33 | "endpoint": "/paths", 34 | "headers_to_pass": ["*"], 35 | "output_encoding": "no-op", 36 | "querystring_params": [ 37 | "course_id" 38 | ], 39 | "backend": [ 40 | { 41 | "url_pattern": "/paths", 42 | "encoding": "no-op" 43 | } 44 | ] 45 | }, 46 | { 47 | "endpoint": "/login", 48 | "method": "POST", 49 | "headers_to_pass": ["*"], 50 | "output_encoding": "no-op", 51 | "backend": [ 52 | { 53 | "url_pattern": "/login", 54 | "encoding": "no-op" 55 | } 56 | ] 57 | }, 58 | { 59 | "endpoint": "/logout", 60 | "headers_to_pass": ["*"], 61 | "output_encoding": "no-op", 62 | "backend": [ 63 | { 64 | "url_pattern": "/logout", 65 | "encoding": "no-op" 66 | } 67 | ] 68 | } 69 | ] 70 | } -------------------------------------------------------------------------------- /06-migrating-product-page/06.1-mocking-response/monolito/top-courses.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "77070", 4 | "title": "Principios SOLID aplicados", 5 | "thumbnail": "https:\/\/pathwright.imgix.net\/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FLfssR9kbRqyx2LaCMxp5%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=b387f292e2d8ac9cd4509923c3148971", 6 | "url": "https:\/\/pro.codely.tv\/library\/principios-solid-aplicados\/77070\/about\/", 7 | "authors": [ 8 | "b4b9ee99-8290-4064-8e3c-e4fd925fe0b9", 9 | "39402ea6-d5a0-4466-918d-e5eef75cc8a9" 10 | ] 11 | }, 12 | { 13 | "id": "66748", 14 | "title": "Arquitectura Hexagonal", 15 | "thumbnail": "https:\/\/pathwright.imgix.net\/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FDYWJYE5RMC0bkd8nCp0u%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=20ec61abaa2b3bcb181b06d9cd5fa5da", 16 | "url": "https:\/\/pro.codely.tv\/library\/arquitectura-hexagonal\/66748\/about\/", 17 | "authors": [ 18 | "b4b9ee99-8290-4064-8e3c-e4fd925fe0b9", 19 | "39402ea6-d5a0-4466-918d-e5eef75cc8a9" 20 | ] 21 | } 22 | ] 23 | -------------------------------------------------------------------------------- /05-requests-and-responses/05.1-splitting-in-multiples-endpoints/monolito/index.php: -------------------------------------------------------------------------------- 1 | $url, 'REQUEST_URL_PATH' => $urlPath]); 17 | 18 | if ($_POST) { 19 | $response = "The POST `$url` doesn't exist!"; 20 | } else { 21 | switch ($urlPath) { 22 | case '': 23 | break; 24 | case 'authors': 25 | $response = (new AuthMiddleware(new AuthorsGetController(), new SessionAuth()))->handle($request); 26 | 27 | break; 28 | case 'courses': 29 | $response = (new AuthMiddleware(new CoursesGetController(), new SessionAuth()))->handle($request); 30 | 31 | break; 32 | case 'paths': 33 | $response = (new AuthMiddleware(new PathsGetController(), new SessionAuth()))->handle($request); 34 | 35 | break; 36 | default: 37 | $response = "The GET `$url` doesn't exist!"; 38 | break; 39 | } 40 | } 41 | 42 | echo $response; 43 | -------------------------------------------------------------------------------- /03-jwt/monolito/auth/SessionAuth.php: -------------------------------------------------------------------------------- 1 | usersPass = $usersPass; 16 | } 17 | 18 | public function isLogged(): bool 19 | { 20 | return isset($_SERVER["HTTP_AUTHORIZATION"]); 21 | } 22 | 23 | public function login(array $request): array 24 | { 25 | $possibleUser = $request['username']; 26 | $possiblePass = $request['pwd']; 27 | 28 | if (!isset($this->usersPass[$possibleUser])) { 29 | return []; 30 | } 31 | 32 | if ($this->usersPass[$possibleUser]['pwd'] !== $possiblePass) { 33 | return []; 34 | } 35 | 36 | return [ 37 | self::USER_ID => $possibleUser, 38 | self::ROLES => $this->usersPass[$possibleUser]['roles'], 39 | self::OTHER => $this->usersPass[$possibleUser]['other'] 40 | ]; 41 | } 42 | 43 | public function startUserSession(array $userData) 44 | { 45 | } 46 | 47 | public function logout() 48 | { 49 | } 50 | 51 | public function get(string $key) 52 | { 53 | $tokenParts = explode('.', $_SERVER["HTTP_AUTHORIZATION"]); 54 | $userData = json_decode(base64_decode($tokenParts[1])); 55 | 56 | return $userData[$key]; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /04-auth-microservice/identity/auth/SessionAuth.php: -------------------------------------------------------------------------------- 1 | usersPass = $usersPass; 16 | } 17 | 18 | public function isLogged(): bool 19 | { 20 | return isset($_SERVER["HTTP_AUTHORIZATION"]); 21 | } 22 | 23 | public function login(array $request): array 24 | { 25 | $possibleUser = $request['username']; 26 | $possiblePass = $request['pwd']; 27 | 28 | if (!isset($this->usersPass[$possibleUser])) { 29 | return []; 30 | } 31 | 32 | if ($this->usersPass[$possibleUser]['pwd'] !== $possiblePass) { 33 | return []; 34 | } 35 | 36 | return [ 37 | self::USER_ID => $possibleUser, 38 | self::ROLES => $this->usersPass[$possibleUser]['roles'], 39 | self::OTHER => $this->usersPass[$possibleUser]['other'] 40 | ]; 41 | } 42 | 43 | public function startUserSession(array $userData) 44 | { 45 | } 46 | 47 | public function logout() 48 | { 49 | } 50 | 51 | public function get(string $key) 52 | { 53 | $tokenParts = explode('.', $_SERVER["HTTP_AUTHORIZATION"]); 54 | $userData = json_decode(base64_decode($tokenParts[1])); 55 | 56 | return $userData[$key]; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /01-monolith/index.php: -------------------------------------------------------------------------------- 1 | handle($_REQUEST); 22 | break; 23 | default: 24 | $response = "The POST `$url` doesn't exist!"; 25 | break; 26 | } 27 | } else { 28 | switch ($url) { 29 | case '/': 30 | break; 31 | case '/courses': 32 | $response = (new AuthMiddleware(new CoursesGetController(), new SessionAuth($usersPass)))->handle($_REQUEST); 33 | 34 | break; 35 | case '/login': 36 | $response = (new LoginPostController(new SessionAuth($usersPass)))->handle($_REQUEST); 37 | break; 38 | case '/logout': 39 | $response = (new LogoutController(new SessionAuth($usersPass)))->handle($_REQUEST); 40 | break; 41 | default: 42 | $response = "The GET `$url` doesn't exist!"; 43 | break; 44 | } 45 | } 46 | 47 | echo $response; 48 | -------------------------------------------------------------------------------- /06-migrating-product-page/06.2-order-petitions/monolito/top-courses.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "77070", 4 | "title": "Principios SOLID aplicados", 5 | "thumbnail": "https:\/\/pathwright.imgix.net\/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FLfssR9kbRqyx2LaCMxp5%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=b387f292e2d8ac9cd4509923c3148971", 6 | "url": "https:\/\/pro.codely.tv\/library\/principios-solid-aplicados\/77070\/about\/", 7 | "authors": [ 8 | "b4b9ee99-8290-4064-8e3c-e4fd925fe0b9", 9 | "39402ea6-d5a0-4466-918d-e5eef75cc8a9" 10 | ], 11 | "price_plan_id": "4c5be45d-799b-49c5-93bc-859a832a2a65" 12 | }, 13 | { 14 | "id": "66748", 15 | "title": "Arquitectura Hexagonal", 16 | "thumbnail": "https:\/\/pathwright.imgix.net\/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FDYWJYE5RMC0bkd8nCp0u%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=20ec61abaa2b3bcb181b06d9cd5fa5da", 17 | "url": "https:\/\/pro.codely.tv\/library\/arquitectura-hexagonal\/66748\/about\/", 18 | "authors": [ 19 | "b4b9ee99-8290-4064-8e3c-e4fd925fe0b9", 20 | "39402ea6-d5a0-4466-918d-e5eef75cc8a9" 21 | ], 22 | "price_plan_id": "4c5be45d-799b-49c5-93bc-859a832a2a65" 23 | } 24 | ] 25 | -------------------------------------------------------------------------------- /05-requests-and-responses/05.2-serializing/monolito/index.php: -------------------------------------------------------------------------------- 1 | $url, 'REQUEST_URL_PATH' => $urlPath]); 18 | 19 | if ($_POST) { 20 | $response = "The POST `$url` doesn't exist!"; 21 | } else { 22 | switch ($urlPath) { 23 | case '': 24 | break; 25 | case 'authors': 26 | $response = (new AuthMiddleware(new AuthorsGetController(), new SessionAuth()))->handle($request); 27 | 28 | break; 29 | case 'courses': 30 | $response = (new AuthMiddleware(new CoursesGetController(), new SessionAuth()))->handle($request); 31 | 32 | break; 33 | case 'paths': 34 | $response = (new AuthMiddleware(new PathsGetController(), new SessionAuth()))->handle($request); 35 | 36 | break; 37 | case 'related-courses': 38 | $response = (new AuthMiddleware(new RelatedCoursesGetController(), new SessionAuth()))->handle($request); 39 | 40 | break; 41 | default: 42 | $response = "The GET `$url` doesn't exist!"; 43 | break; 44 | } 45 | } 46 | 47 | echo $response; 48 | -------------------------------------------------------------------------------- /05-requests-and-responses/05.3-standarization/monolito/index.php: -------------------------------------------------------------------------------- 1 | $url, 'REQUEST_URL_PATH' => $urlPath]); 18 | 19 | if ($_POST) { 20 | $response = "The POST `$url` doesn't exist!"; 21 | } else { 22 | switch ($urlPath) { 23 | case '': 24 | break; 25 | case 'authors': 26 | $response = (new AuthMiddleware(new AuthorsGetController(), new SessionAuth()))->handle($request); 27 | 28 | break; 29 | case 'courses': 30 | $response = (new AuthMiddleware(new CoursesGetController(), new SessionAuth()))->handle($request); 31 | 32 | break; 33 | case 'paths': 34 | $response = (new AuthMiddleware(new PathsGetController(), new SessionAuth()))->handle($request); 35 | 36 | break; 37 | case 'related-courses': 38 | $response = (new AuthMiddleware(new RelatedCoursesGetController(), new SessionAuth()))->handle($request); 39 | 40 | break; 41 | default: 42 | $response = "The GET `$url` doesn't exist!"; 43 | break; 44 | } 45 | } 46 | 47 | echo $response; 48 | -------------------------------------------------------------------------------- /06-migrating-product-page/06.1-mocking-response/monolito/index.php: -------------------------------------------------------------------------------- 1 | $url, 'REQUEST_URL_PATH' => $urlPath]); 18 | 19 | if ($_POST) { 20 | $response = "The POST `$url` doesn't exist!"; 21 | } else { 22 | switch ($urlPath) { 23 | case '': 24 | break; 25 | case 'authors': 26 | $response = (new AuthMiddleware(new AuthorsGetController(), new SessionAuth()))->handle($request); 27 | 28 | break; 29 | case 'courses': 30 | $response = (new AuthMiddleware(new CoursesGetController(), new SessionAuth()))->handle($request); 31 | 32 | break; 33 | case 'paths': 34 | $response = (new AuthMiddleware(new PathsGetController(), new SessionAuth()))->handle($request); 35 | 36 | break; 37 | case 'related-courses': 38 | $response = (new AuthMiddleware(new RelatedCoursesGetController(), new SessionAuth()))->handle($request); 39 | 40 | break; 41 | default: 42 | $response = "The GET `$url` doesn't exist!"; 43 | break; 44 | } 45 | } 46 | 47 | echo $response; 48 | -------------------------------------------------------------------------------- /01-monolith/auth/SessionAuth.php: -------------------------------------------------------------------------------- 1 | usersPass = $usersPass; 17 | } 18 | 19 | public function isLogged(): bool 20 | { 21 | return $this->get(self::USER_ID) != ''; 22 | } 23 | 24 | public function login(array $request): array 25 | { 26 | $possibleUser = $request['username']; 27 | $possiblePass = $request['pwd']; 28 | 29 | if (!isset($this->usersPass[$possibleUser])) { 30 | return []; 31 | } 32 | 33 | if ($this->usersPass[$possibleUser]['pwd'] !== $possiblePass) { 34 | return []; 35 | } 36 | 37 | return [ 38 | self::USER_ID => $possibleUser, 39 | self::ROLES => $this->usersPass[$possibleUser]['roles'], 40 | self::OTHER => $this->usersPass[$possibleUser]['other'] 41 | ]; 42 | } 43 | 44 | public function startUserSession(array $userData) 45 | { 46 | foreach ($userData as $key => $value) { 47 | $_SESSION[$key] = $value; 48 | } 49 | } 50 | 51 | public function logout() 52 | { 53 | $_SESSION = array(); 54 | if (ini_get("session.use_cookies")) { 55 | $params = session_get_cookie_params(); 56 | setcookie(session_name(), '', time() - 42000, 57 | $params["path"], $params["domain"], 58 | $params["secure"], $params["httponly"] 59 | ); 60 | } 61 | session_destroy(); 62 | } 63 | 64 | public function get(string $key) 65 | { 66 | return $_SESSION[$key]; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /06-migrating-product-page/06.2-order-petitions/monolito/index.php: -------------------------------------------------------------------------------- 1 | $url, 'REQUEST_URL_PATH' => $urlPath]); 19 | 20 | if ($_POST) { 21 | $response = "The POST `$url` doesn't exist!"; 22 | } else { 23 | switch ($urlPath) { 24 | case '': 25 | break; 26 | case 'authors': 27 | $response = (new AuthMiddleware(new AuthorsGetController(), new SessionAuth()))->handle($request); 28 | 29 | break; 30 | case 'courses': 31 | $response = (new AuthMiddleware(new CoursesGetController(), new SessionAuth()))->handle($request); 32 | 33 | break; 34 | case 'paths': 35 | $response = (new AuthMiddleware(new PathsGetController(), new SessionAuth()))->handle($request); 36 | 37 | break; 38 | case 'related-courses': 39 | $response = (new AuthMiddleware(new RelatedCoursesGetController(), new SessionAuth()))->handle($request); 40 | 41 | break; 42 | case 'pricing-plan': 43 | $response = (new AuthMiddleware(new PricingPlanGetController(), new SessionAuth()))->handle($request); 44 | 45 | break; 46 | default: 47 | $response = "The GET `$url` doesn't exist!"; 48 | break; 49 | } 50 | } 51 | 52 | echo $response; 53 | -------------------------------------------------------------------------------- /03-jwt/monolito/index.php: -------------------------------------------------------------------------------- 1 | handle($_REQUEST); 25 | break; 26 | default: 27 | $response = "The POST `$url` doesn't exist!"; 28 | break; 29 | } 30 | } else { 31 | switch ($url) { 32 | case '/': 33 | break; 34 | case '/authors': 35 | $response = (new AuthMiddleware(new AuthorsGetController(), new SessionAuth($usersPass)))->handle($_REQUEST); 36 | 37 | break; 38 | case '/courses': 39 | $response = (new AuthMiddleware(new CoursesGetController(), new SessionAuth($usersPass)))->handle($_REQUEST); 40 | 41 | break; 42 | case '/paths': 43 | $response = (new AuthMiddleware(new PathsGetController(), new SessionAuth($usersPass)))->handle($_REQUEST); 44 | 45 | break; 46 | case '/login': 47 | $response = (new LoginPostController(new SessionAuth($usersPass)))->handle($_REQUEST); 48 | 49 | break; 50 | case '/logout': 51 | $response = (new LogoutController(new SessionAuth($usersPass)))->handle($_REQUEST); 52 | 53 | break; 54 | case '/jwk': 55 | $response = (new JWKController())->handle($_REQUEST); 56 | 57 | break; 58 | default: 59 | $response = "The GET `$url` doesn't exist!"; 60 | break; 61 | } 62 | } 63 | 64 | echo $response; 65 | -------------------------------------------------------------------------------- /01-monolith/README.md: -------------------------------------------------------------------------------- 1 | # De monolito a microservicios con API Gateway 2 | 3 | ## 🚀 Environment setup 4 | 5 | 1. Clone this project: `git clone https://github.com/CodelyTV/from-monolith-to-microservices-using-api-gateway from-monolith-to-microservices-using-api-gateway` 6 | 2. Move to the project folder: `cd from-monolith-to-microservices-using-api-gateway` 7 | 3. Move to the stage you want to test: `cd 00-monolith` 8 | 4. Choose the option you prefer: 9 | * 🐘 With local PHP server: `php -S localhost:8081 index.php` 10 | * 🐳 With Docker: `docker-compose up` 11 | 12 | ## 🤹‍♂️ Available endpoints 13 | 14 | * See [`example-curls.sh`](example-curls.sh) for specific `curl` calls. 15 | * `POST /login`: HTTP login. Valid combinations [here](utils.php). 16 | * `GET /courses?course_id=77070`: All the information regarding the `77070` course including its path, authors, and more. Response example: 17 | ```json 18 | { 19 | "title": "Principios SOLID aplicados", 20 | "thumbnail": "https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FLfssR9kbRqyx2LaCMxp5%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=b387f292e2d8ac9cd4509923c3148971", 21 | "url": "https://pro.codely.tv/library/principios-solid-aplicados/77070/about/", 22 | "authors": [ 23 | { 24 | "name": "Javier Ferrer", 25 | "thumbnail": "https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FCERdtqBcSWe4hKpoUeoz%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=1f5c7a1eda9180240c52901a24af43df" 26 | }, 27 | { 28 | "name": "Rafa Gómez", 29 | "thumbnail": "https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FSkO7YnieTieDgWfev170%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=3a11c0499b9dc9f31168e1b0285fb664" 30 | } 31 | ], 32 | "path": [ 33 | { 34 | "title": "Qué son los principios SOLID (Huyendo de STUPID) 🦄 - ¡Disponible sin registro! 💸", 35 | "visible": true, 36 | "order": 1 37 | }, 38 | { 39 | "title": "UML, ese gran denostado 🤕", 40 | "visible": true, 41 | "order": 2 42 | }, 43 | { 44 | "title": "Principio de Responsabilidad Única 🕺", 45 | "visible": true, 46 | "order": 3 47 | } 48 | ] 49 | } 50 | ``` 51 | -------------------------------------------------------------------------------- /03-jwt/gateway/krakend.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "timeout": "3000ms", 4 | "port": 8080, 5 | "cache_ttl": "300s", 6 | "host": [ 7 | "http://monolith:8081" 8 | ], 9 | "endpoints": [ 10 | { 11 | "endpoint": "/authors", 12 | "headers_to_pass": ["*"], 13 | "output_encoding": "no-op", 14 | "backend": [ 15 | { 16 | "url_pattern": "/authors", 17 | "encoding": "no-op" 18 | } 19 | ], 20 | "extra_config": { 21 | "github.com/devopsfaith/krakend-jose/validator": { 22 | "alg": "HS256", 23 | "audience": ["http://api.company.com"], 24 | "roles_key": "roles", 25 | "issuer": "http://monoli.th", 26 | "roles": ["user", "admin"], 27 | "jwk-url": "http://monolith:8081/jwk", 28 | "disable_jwk_security": true 29 | } 30 | } 31 | }, 32 | { 33 | "endpoint": "/courses", 34 | "headers_to_pass": ["*"], 35 | "output_encoding": "no-op", 36 | "backend": [ 37 | { 38 | "url_pattern": "/courses", 39 | "encoding": "no-op" 40 | } 41 | ], 42 | "extra_config": { 43 | "github.com/devopsfaith/krakend-jose/validator": { 44 | "alg": "HS256", 45 | "audience": ["http://api.company.com"], 46 | "roles_key": "roles", 47 | "issuer": "http://monoli.th", 48 | "roles": ["user", "admin"], 49 | "jwk-url": "http://monolith:8081/jwk", 50 | "disable_jwk_security": true 51 | } 52 | } 53 | }, 54 | { 55 | "endpoint": "/paths", 56 | "headers_to_pass": ["*"], 57 | "output_encoding": "no-op", 58 | "querystring_params": [ 59 | "course_id" 60 | ], 61 | "backend": [ 62 | { 63 | "url_pattern": "/paths", 64 | "encoding": "no-op" 65 | } 66 | ], 67 | "extra_config": { 68 | "github.com/devopsfaith/krakend-jose/validator": { 69 | "alg": "HS256", 70 | "audience": ["http://api.company.com"], 71 | "roles_key": "roles", 72 | "issuer": "http://monoli.th", 73 | "roles": ["user", "admin"], 74 | "jwk-url": "http://monolith:8081/jwk", 75 | "disable_jwk_security": true 76 | } 77 | } 78 | }, 79 | { 80 | "endpoint": "/login", 81 | "method": "POST", 82 | "headers_to_pass": ["*"], 83 | "backend": [ 84 | { 85 | "url_pattern": "/login" 86 | } 87 | ], 88 | "extra_config": { 89 | "github.com/devopsfaith/krakend-jose/signer": { 90 | "alg": "HS256", 91 | "kid": "sim2", 92 | "keys-to-sign": ["access_token"], 93 | "jwk-url": "http://monolith:8081/jwk", 94 | "disable_jwk_security": true 95 | } 96 | } 97 | }, 98 | { 99 | "endpoint": "/logout", 100 | "headers_to_pass": ["*"], 101 | "output_encoding": "no-op", 102 | "backend": [ 103 | { 104 | "url_pattern": "/logout", 105 | "encoding": "no-op" 106 | } 107 | ] 108 | } 109 | ] 110 | } -------------------------------------------------------------------------------- /04-auth-microservice/gateway/krakend.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "timeout": "3000ms", 4 | "port": 8080, 5 | "cache_ttl": "300s", 6 | "host": [ 7 | "http://monolith:8081" 8 | ], 9 | "endpoints": [ 10 | { 11 | "endpoint": "/authors", 12 | "headers_to_pass": ["*"], 13 | "output_encoding": "no-op", 14 | "backend": [ 15 | { 16 | "url_pattern": "/authors", 17 | "encoding": "no-op" 18 | } 19 | ], 20 | "extra_config": { 21 | "github.com/devopsfaith/krakend-jose/validator": { 22 | "alg": "HS256", 23 | "audience": ["http://api.company.com"], 24 | "roles_key": "roles", 25 | "issuer": "http://monoli.th", 26 | "roles": ["user", "admin"], 27 | "jwk-url": "http://identity:8082/jwk", 28 | "disable_jwk_security": true 29 | } 30 | } 31 | }, 32 | { 33 | "endpoint": "/courses", 34 | "headers_to_pass": ["*"], 35 | "output_encoding": "no-op", 36 | "backend": [ 37 | { 38 | "url_pattern": "/courses", 39 | "encoding": "no-op" 40 | } 41 | ], 42 | "extra_config": { 43 | "github.com/devopsfaith/krakend-jose/validator": { 44 | "alg": "HS256", 45 | "audience": ["http://api.company.com"], 46 | "roles_key": "roles", 47 | "issuer": "http://monoli.th", 48 | "roles": ["user", "admin"], 49 | "jwk-url": "http://identity:8082/jwk", 50 | "disable_jwk_security": true 51 | } 52 | } 53 | }, 54 | { 55 | "endpoint": "/paths", 56 | "headers_to_pass": ["*"], 57 | "output_encoding": "no-op", 58 | "querystring_params": [ 59 | "course_id" 60 | ], 61 | "backend": [ 62 | { 63 | "url_pattern": "/paths", 64 | "encoding": "no-op" 65 | } 66 | ], 67 | "extra_config": { 68 | "github.com/devopsfaith/krakend-jose/validator": { 69 | "alg": "HS256", 70 | "audience": ["http://api.company.com"], 71 | "roles_key": "roles", 72 | "issuer": "http://monoli.th", 73 | "roles": ["user", "admin"], 74 | "jwk-url": "http://identity:8082/jwk", 75 | "disable_jwk_security": true 76 | } 77 | } 78 | }, 79 | { 80 | "endpoint": "/login", 81 | "method": "POST", 82 | "headers_to_pass": ["*"], 83 | "backend": [ 84 | { 85 | "url_pattern": "/login", 86 | "host": ["http://identity:8082"] 87 | } 88 | ], 89 | "extra_config": { 90 | "github.com/devopsfaith/krakend-jose/signer": { 91 | "alg": "HS256", 92 | "kid": "sim2", 93 | "keys-to-sign": ["access_token"], 94 | "jwk-url": "http://identity:8082/jwk", 95 | "disable_jwk_security": true 96 | } 97 | } 98 | }, 99 | { 100 | "endpoint": "/logout", 101 | "headers_to_pass": ["*"], 102 | "backend": [ 103 | { 104 | "url_pattern": "/logout", 105 | "host": ["http://identity:8082"] 106 | } 107 | ] 108 | } 109 | ] 110 | } -------------------------------------------------------------------------------- /03-jwt/monolito/controller/PathsGetController.php: -------------------------------------------------------------------------------- 1 | [ 9 | [ 10 | 'title' => 'Qué son los principios SOLID (Huyendo de STUPID) 🦄 - ¡Disponible sin registro! 💸', 11 | 'visible' => true, 12 | 'order' => 1, 13 | ], 14 | [ 15 | 'title' => 'UML, ese gran denostado 🤕', 16 | 'visible' => true, 17 | 'order' => 2, 18 | ], 19 | [ 20 | 'title' => 'Principio de Responsabilidad Única 🕺', 21 | 'visible' => true, 22 | 'order' => 3, 23 | ], 24 | ], 25 | '66748' => [ 26 | [ 27 | 'title' => 'Bienvenida al curso 👋 ¡Disponible sin registro! 💸', 28 | 'visible' => true, 29 | 'order' => 1, 30 | ], 31 | [ 32 | 'title' => 'Qué es la Arquitectura de Software 💎', 33 | 'visible' => true, 34 | 'order' => 2, 35 | ], 36 | [ 37 | 'title' => 'Qué es la Arquitectura Hexagonal ⬢', 38 | 'visible' => true, 39 | 'order' => 3, 40 | ], 41 | ], 42 | '90916' => [ 43 | [ 44 | 'title' => '🤔 ¿Qué es el testing y qué aporta? ¿Por qué deberíamos testear? - Disponible sin registro', 45 | 'visible' => true, 46 | 'order' => 1, 47 | ], 48 | [ 49 | 'title' => '🚀 ¡Al turrón!: Nuestros primeros tests', 50 | 'visible' => true, 51 | 'order' => 2, 52 | ], 53 | [ 54 | 'title' => '🌀 Exprimiendo nuestro framework de testing (PHP, Java, JavaScript, y Scala)', 55 | 'visible' => true, 56 | 'order' => 3, 57 | ], 58 | ], 59 | '87157' => [ 60 | [ 61 | 'title' => '👋 DDD en 20 minutos - Disponible sin registro', 62 | 'visible' => true, 63 | 'order' => 1, 64 | ], 65 | [ 66 | 'title' => '🚀 Bounded Contexts, subdomains y modules: Creando nuestra aplicación', 67 | 'visible' => true, 68 | 'order' => 2, 69 | ], 70 | [ 71 | 'title' => '🎯 Arquitectura Hexagonal', 72 | 'visible' => true, 73 | 'order' => 3, 74 | ], 75 | ], 76 | ]; 77 | 78 | public function handle(array $request): string 79 | { 80 | if (!isset($request['course_id'])) { 81 | return $this->jsonResponse(self::PATHS); 82 | } 83 | 84 | if (!isset(self::PATHS[$request['course_id']])) { 85 | return $this->jsonResponse([]); 86 | } 87 | 88 | return $this->jsonResponse(self::PATHS[$request['course_id']]); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /04-auth-microservice/monolito/controller/PathsGetController.php: -------------------------------------------------------------------------------- 1 | [ 9 | [ 10 | 'title' => 'Qué son los principios SOLID (Huyendo de STUPID) 🦄 - ¡Disponible sin registro! 💸', 11 | 'visible' => true, 12 | 'order' => 1, 13 | ], 14 | [ 15 | 'title' => 'UML, ese gran denostado 🤕', 16 | 'visible' => true, 17 | 'order' => 2, 18 | ], 19 | [ 20 | 'title' => 'Principio de Responsabilidad Única 🕺', 21 | 'visible' => true, 22 | 'order' => 3, 23 | ], 24 | ], 25 | '66748' => [ 26 | [ 27 | 'title' => 'Bienvenida al curso 👋 ¡Disponible sin registro! 💸', 28 | 'visible' => true, 29 | 'order' => 1, 30 | ], 31 | [ 32 | 'title' => 'Qué es la Arquitectura de Software 💎', 33 | 'visible' => true, 34 | 'order' => 2, 35 | ], 36 | [ 37 | 'title' => 'Qué es la Arquitectura Hexagonal ⬢', 38 | 'visible' => true, 39 | 'order' => 3, 40 | ], 41 | ], 42 | '90916' => [ 43 | [ 44 | 'title' => '🤔 ¿Qué es el testing y qué aporta? ¿Por qué deberíamos testear? - Disponible sin registro', 45 | 'visible' => true, 46 | 'order' => 1, 47 | ], 48 | [ 49 | 'title' => '🚀 ¡Al turrón!: Nuestros primeros tests', 50 | 'visible' => true, 51 | 'order' => 2, 52 | ], 53 | [ 54 | 'title' => '🌀 Exprimiendo nuestro framework de testing (PHP, Java, JavaScript, y Scala)', 55 | 'visible' => true, 56 | 'order' => 3, 57 | ], 58 | ], 59 | '87157' => [ 60 | [ 61 | 'title' => '👋 DDD en 20 minutos - Disponible sin registro', 62 | 'visible' => true, 63 | 'order' => 1, 64 | ], 65 | [ 66 | 'title' => '🚀 Bounded Contexts, subdomains y modules: Creando nuestra aplicación', 67 | 'visible' => true, 68 | 'order' => 2, 69 | ], 70 | [ 71 | 'title' => '🎯 Arquitectura Hexagonal', 72 | 'visible' => true, 73 | 'order' => 3, 74 | ], 75 | ], 76 | ]; 77 | 78 | public function handle(array $request): string 79 | { 80 | if (!isset($request['course_id'])) { 81 | return $this->jsonResponse(self::PATHS); 82 | } 83 | 84 | if (!isset(self::PATHS[$request['course_id']])) { 85 | return $this->jsonResponse([]); 86 | } 87 | 88 | return $this->jsonResponse(self::PATHS[$request['course_id']]); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /03-jwt/monolito/controller/AuthorsGetController.php: -------------------------------------------------------------------------------- 1 | jsonResponse( 10 | [ 11 | [ 12 | 'id' => 'b4b9ee99-8290-4064-8e3c-e4fd925fe0b9', 13 | 'name' => 'Javier Ferrer', 14 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FCERdtqBcSWe4hKpoUeoz%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=1f5c7a1eda9180240c52901a24af43df', 15 | ], 16 | [ 17 | 'id' => '39402ea6-d5a0-4466-918d-e5eef75cc8a9', 18 | 'name' => 'Rafa Gómez', 19 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FSkO7YnieTieDgWfev170%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=3a11c0499b9dc9f31168e1b0285fb664', 20 | ], 21 | [ 22 | 'id' => '6a8344bc-d527-4100-a83a-d2bb298fdbf7', 23 | 'name' => 'Jose Armesto', 24 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2Fc9nWZL8TlquzsW6So1jV%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=9a6d348c3efd4df8f5076ff984f18d68', 25 | ], 26 | [ 27 | 'id' => '9ebe81d3-0dd6-48d2-9e3a-2d60fd348b29', 28 | 'name' => 'Ramón Aranda', 29 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2F1v8Hwh0QgKLsQGBvzZ0h%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=e06740a20d79cdd416391d028daf3457', 30 | ], 31 | [ 32 | 'id' => 'ce4a0077-2062-49f9-aaeb-a09ac3888f31', 33 | 'name' => 'Jordi Llonch', 34 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FzzKesprROSzkyK8iwAbn%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=0179a7c0e20f2e989393ddd2a95e5f80', 35 | ], 36 | ] 37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /05-requests-and-responses/05.2-serializing/monolito/controller/PathsGetController.php: -------------------------------------------------------------------------------- 1 | [ 9 | [ 10 | 'title' => 'Qué son los principios SOLID (Huyendo de STUPID) 🦄 - ¡Disponible sin registro! 💸', 11 | 'visible' => true, 12 | 'order' => 1, 13 | ], 14 | [ 15 | 'title' => 'UML, ese gran denostado 🤕', 16 | 'visible' => true, 17 | 'order' => 2, 18 | ], 19 | [ 20 | 'title' => 'Principio de Responsabilidad Única 🕺', 21 | 'visible' => true, 22 | 'order' => 3, 23 | ], 24 | ], 25 | '66748' => [ 26 | [ 27 | 'title' => 'Bienvenida al curso 👋 ¡Disponible sin registro! 💸', 28 | 'visible' => true, 29 | 'order' => 1, 30 | ], 31 | [ 32 | 'title' => 'Qué es la Arquitectura de Software 💎', 33 | 'visible' => true, 34 | 'order' => 2, 35 | ], 36 | [ 37 | 'title' => 'Qué es la Arquitectura Hexagonal ⬢', 38 | 'visible' => true, 39 | 'order' => 3, 40 | ], 41 | ], 42 | '90916' => [ 43 | [ 44 | 'title' => '🤔 ¿Qué es el testing y qué aporta? ¿Por qué deberíamos testear? - Disponible sin registro', 45 | 'visible' => true, 46 | 'order' => 1, 47 | ], 48 | [ 49 | 'title' => '🚀 ¡Al turrón!: Nuestros primeros tests', 50 | 'visible' => true, 51 | 'order' => 2, 52 | ], 53 | [ 54 | 'title' => '🌀 Exprimiendo nuestro framework de testing (PHP, Java, JavaScript, y Scala)', 55 | 'visible' => true, 56 | 'order' => 3, 57 | ], 58 | ], 59 | '87157' => [ 60 | [ 61 | 'title' => '👋 DDD en 20 minutos - Disponible sin registro', 62 | 'visible' => true, 63 | 'order' => 1, 64 | ], 65 | [ 66 | 'title' => '🚀 Bounded Contexts, subdomains y modules: Creando nuestra aplicación', 67 | 'visible' => true, 68 | 'order' => 2, 69 | ], 70 | [ 71 | 'title' => '🎯 Arquitectura Hexagonal', 72 | 'visible' => true, 73 | 'order' => 3, 74 | ], 75 | ], 76 | ]; 77 | 78 | public function handle(array $request): string 79 | { 80 | if (!isset($request['course_id'])) { 81 | return $this->jsonResponse(self::PATHS); 82 | } 83 | 84 | if (!isset(self::PATHS[$request['course_id']])) { 85 | return $this->jsonResponse([]); 86 | } 87 | 88 | return $this->jsonResponse(self::PATHS[$request['course_id']]); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /05-requests-and-responses/05.3-standarization/monolito/controller/PathsGetController.php: -------------------------------------------------------------------------------- 1 | [ 9 | [ 10 | 'title' => 'Qué son los principios SOLID (Huyendo de STUPID) 🦄 - ¡Disponible sin registro! 💸', 11 | 'visible' => true, 12 | 'order' => 1, 13 | ], 14 | [ 15 | 'title' => 'UML, ese gran denostado 🤕', 16 | 'visible' => true, 17 | 'order' => 2, 18 | ], 19 | [ 20 | 'title' => 'Principio de Responsabilidad Única 🕺', 21 | 'visible' => true, 22 | 'order' => 3, 23 | ], 24 | ], 25 | '66748' => [ 26 | [ 27 | 'title' => 'Bienvenida al curso 👋 ¡Disponible sin registro! 💸', 28 | 'visible' => true, 29 | 'order' => 1, 30 | ], 31 | [ 32 | 'title' => 'Qué es la Arquitectura de Software 💎', 33 | 'visible' => true, 34 | 'order' => 2, 35 | ], 36 | [ 37 | 'title' => 'Qué es la Arquitectura Hexagonal ⬢', 38 | 'visible' => true, 39 | 'order' => 3, 40 | ], 41 | ], 42 | '90916' => [ 43 | [ 44 | 'title' => '🤔 ¿Qué es el testing y qué aporta? ¿Por qué deberíamos testear? - Disponible sin registro', 45 | 'visible' => true, 46 | 'order' => 1, 47 | ], 48 | [ 49 | 'title' => '🚀 ¡Al turrón!: Nuestros primeros tests', 50 | 'visible' => true, 51 | 'order' => 2, 52 | ], 53 | [ 54 | 'title' => '🌀 Exprimiendo nuestro framework de testing (PHP, Java, JavaScript, y Scala)', 55 | 'visible' => true, 56 | 'order' => 3, 57 | ], 58 | ], 59 | '87157' => [ 60 | [ 61 | 'title' => '👋 DDD en 20 minutos - Disponible sin registro', 62 | 'visible' => true, 63 | 'order' => 1, 64 | ], 65 | [ 66 | 'title' => '🚀 Bounded Contexts, subdomains y modules: Creando nuestra aplicación', 67 | 'visible' => true, 68 | 'order' => 2, 69 | ], 70 | [ 71 | 'title' => '🎯 Arquitectura Hexagonal', 72 | 'visible' => true, 73 | 'order' => 3, 74 | ], 75 | ], 76 | ]; 77 | 78 | public function handle(array $request): string 79 | { 80 | if (!isset($request['course_id'])) { 81 | return $this->jsonResponse(self::PATHS); 82 | } 83 | 84 | if (!isset(self::PATHS[$request['course_id']])) { 85 | return $this->jsonResponse([]); 86 | } 87 | 88 | return $this->jsonResponse(self::PATHS[$request['course_id']]); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /06-migrating-product-page/06.1-mocking-response/monolito/controller/PathsGetController.php: -------------------------------------------------------------------------------- 1 | [ 9 | [ 10 | 'title' => 'Qué son los principios SOLID (Huyendo de STUPID) 🦄 - ¡Disponible sin registro! 💸', 11 | 'visible' => true, 12 | 'order' => 1, 13 | ], 14 | [ 15 | 'title' => 'UML, ese gran denostado 🤕', 16 | 'visible' => true, 17 | 'order' => 2, 18 | ], 19 | [ 20 | 'title' => 'Principio de Responsabilidad Única 🕺', 21 | 'visible' => true, 22 | 'order' => 3, 23 | ], 24 | ], 25 | '66748' => [ 26 | [ 27 | 'title' => 'Bienvenida al curso 👋 ¡Disponible sin registro! 💸', 28 | 'visible' => true, 29 | 'order' => 1, 30 | ], 31 | [ 32 | 'title' => 'Qué es la Arquitectura de Software 💎', 33 | 'visible' => true, 34 | 'order' => 2, 35 | ], 36 | [ 37 | 'title' => 'Qué es la Arquitectura Hexagonal ⬢', 38 | 'visible' => true, 39 | 'order' => 3, 40 | ], 41 | ], 42 | '90916' => [ 43 | [ 44 | 'title' => '🤔 ¿Qué es el testing y qué aporta? ¿Por qué deberíamos testear? - Disponible sin registro', 45 | 'visible' => true, 46 | 'order' => 1, 47 | ], 48 | [ 49 | 'title' => '🚀 ¡Al turrón!: Nuestros primeros tests', 50 | 'visible' => true, 51 | 'order' => 2, 52 | ], 53 | [ 54 | 'title' => '🌀 Exprimiendo nuestro framework de testing (PHP, Java, JavaScript, y Scala)', 55 | 'visible' => true, 56 | 'order' => 3, 57 | ], 58 | ], 59 | '87157' => [ 60 | [ 61 | 'title' => '👋 DDD en 20 minutos - Disponible sin registro', 62 | 'visible' => true, 63 | 'order' => 1, 64 | ], 65 | [ 66 | 'title' => '🚀 Bounded Contexts, subdomains y modules: Creando nuestra aplicación', 67 | 'visible' => true, 68 | 'order' => 2, 69 | ], 70 | [ 71 | 'title' => '🎯 Arquitectura Hexagonal', 72 | 'visible' => true, 73 | 'order' => 3, 74 | ], 75 | ], 76 | ]; 77 | 78 | public function handle(array $request): string 79 | { 80 | if (!isset($request['course_id'])) { 81 | return $this->jsonResponse(self::PATHS); 82 | } 83 | 84 | if (!isset(self::PATHS[$request['course_id']])) { 85 | return $this->jsonResponse([]); 86 | } 87 | 88 | return $this->jsonResponse(self::PATHS[$request['course_id']]); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /06-migrating-product-page/06.2-order-petitions/monolito/controller/PathsGetController.php: -------------------------------------------------------------------------------- 1 | [ 9 | [ 10 | 'title' => 'Qué son los principios SOLID (Huyendo de STUPID) 🦄 - ¡Disponible sin registro! 💸', 11 | 'visible' => true, 12 | 'order' => 1, 13 | ], 14 | [ 15 | 'title' => 'UML, ese gran denostado 🤕', 16 | 'visible' => true, 17 | 'order' => 2, 18 | ], 19 | [ 20 | 'title' => 'Principio de Responsabilidad Única 🕺', 21 | 'visible' => true, 22 | 'order' => 3, 23 | ], 24 | ], 25 | '66748' => [ 26 | [ 27 | 'title' => 'Bienvenida al curso 👋 ¡Disponible sin registro! 💸', 28 | 'visible' => true, 29 | 'order' => 1, 30 | ], 31 | [ 32 | 'title' => 'Qué es la Arquitectura de Software 💎', 33 | 'visible' => true, 34 | 'order' => 2, 35 | ], 36 | [ 37 | 'title' => 'Qué es la Arquitectura Hexagonal ⬢', 38 | 'visible' => true, 39 | 'order' => 3, 40 | ], 41 | ], 42 | '90916' => [ 43 | [ 44 | 'title' => '🤔 ¿Qué es el testing y qué aporta? ¿Por qué deberíamos testear? - Disponible sin registro', 45 | 'visible' => true, 46 | 'order' => 1, 47 | ], 48 | [ 49 | 'title' => '🚀 ¡Al turrón!: Nuestros primeros tests', 50 | 'visible' => true, 51 | 'order' => 2, 52 | ], 53 | [ 54 | 'title' => '🌀 Exprimiendo nuestro framework de testing (PHP, Java, JavaScript, y Scala)', 55 | 'visible' => true, 56 | 'order' => 3, 57 | ], 58 | ], 59 | '87157' => [ 60 | [ 61 | 'title' => '👋 DDD en 20 minutos - Disponible sin registro', 62 | 'visible' => true, 63 | 'order' => 1, 64 | ], 65 | [ 66 | 'title' => '🚀 Bounded Contexts, subdomains y modules: Creando nuestra aplicación', 67 | 'visible' => true, 68 | 'order' => 2, 69 | ], 70 | [ 71 | 'title' => '🎯 Arquitectura Hexagonal', 72 | 'visible' => true, 73 | 'order' => 3, 74 | ], 75 | ], 76 | ]; 77 | 78 | public function handle(array $request): string 79 | { 80 | if (!isset($request['course_id'])) { 81 | return $this->jsonResponse(self::PATHS); 82 | } 83 | 84 | if (!isset(self::PATHS[$request['course_id']])) { 85 | return $this->jsonResponse([]); 86 | } 87 | 88 | return $this->jsonResponse(self::PATHS[$request['course_id']]); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /04-auth-microservice/monolito/controller/AuthorsGetController.php: -------------------------------------------------------------------------------- 1 | jsonResponse( 10 | [ 11 | [ 12 | 'id' => 'b4b9ee99-8290-4064-8e3c-e4fd925fe0b9', 13 | 'name' => 'Javier Ferrer', 14 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FCERdtqBcSWe4hKpoUeoz%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=1f5c7a1eda9180240c52901a24af43df', 15 | ], 16 | [ 17 | 'id' => '39402ea6-d5a0-4466-918d-e5eef75cc8a9', 18 | 'name' => 'Rafa Gómez', 19 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FSkO7YnieTieDgWfev170%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=3a11c0499b9dc9f31168e1b0285fb664', 20 | ], 21 | [ 22 | 'id' => '6a8344bc-d527-4100-a83a-d2bb298fdbf7', 23 | 'name' => 'Jose Armesto', 24 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2Fc9nWZL8TlquzsW6So1jV%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=9a6d348c3efd4df8f5076ff984f18d68', 25 | ], 26 | [ 27 | 'id' => '9ebe81d3-0dd6-48d2-9e3a-2d60fd348b29', 28 | 'name' => 'Ramón Aranda', 29 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2F1v8Hwh0QgKLsQGBvzZ0h%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=e06740a20d79cdd416391d028daf3457', 30 | ], 31 | [ 32 | 'id' => 'ce4a0077-2062-49f9-aaeb-a09ac3888f31', 33 | 'name' => 'Jordi Llonch', 34 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FzzKesprROSzkyK8iwAbn%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=0179a7c0e20f2e989393ddd2a95e5f80', 35 | ], 36 | ] 37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /05-requests-and-responses/05.1-splitting-in-multiples-endpoints/monolito/controller/PathsGetController.php: -------------------------------------------------------------------------------- 1 | [ 9 | [ 10 | 'title' => 'Qué son los principios SOLID (Huyendo de STUPID) 🦄 - ¡Disponible sin registro! 💸', 11 | 'visible' => true, 12 | 'order' => 1, 13 | ], 14 | [ 15 | 'title' => 'UML, ese gran denostado 🤕', 16 | 'visible' => true, 17 | 'order' => 2, 18 | ], 19 | [ 20 | 'title' => 'Principio de Responsabilidad Única 🕺', 21 | 'visible' => true, 22 | 'order' => 3, 23 | ], 24 | ], 25 | '66748' => [ 26 | [ 27 | 'title' => 'Bienvenida al curso 👋 ¡Disponible sin registro! 💸', 28 | 'visible' => true, 29 | 'order' => 1, 30 | ], 31 | [ 32 | 'title' => 'Qué es la Arquitectura de Software 💎', 33 | 'visible' => true, 34 | 'order' => 2, 35 | ], 36 | [ 37 | 'title' => 'Qué es la Arquitectura Hexagonal ⬢', 38 | 'visible' => true, 39 | 'order' => 3, 40 | ], 41 | ], 42 | '90916' => [ 43 | [ 44 | 'title' => '🤔 ¿Qué es el testing y qué aporta? ¿Por qué deberíamos testear? - Disponible sin registro', 45 | 'visible' => true, 46 | 'order' => 1, 47 | ], 48 | [ 49 | 'title' => '🚀 ¡Al turrón!: Nuestros primeros tests', 50 | 'visible' => true, 51 | 'order' => 2, 52 | ], 53 | [ 54 | 'title' => '🌀 Exprimiendo nuestro framework de testing (PHP, Java, JavaScript, y Scala)', 55 | 'visible' => true, 56 | 'order' => 3, 57 | ], 58 | ], 59 | '87157' => [ 60 | [ 61 | 'title' => '👋 DDD en 20 minutos - Disponible sin registro', 62 | 'visible' => true, 63 | 'order' => 1, 64 | ], 65 | [ 66 | 'title' => '🚀 Bounded Contexts, subdomains y modules: Creando nuestra aplicación', 67 | 'visible' => true, 68 | 'order' => 2, 69 | ], 70 | [ 71 | 'title' => '🎯 Arquitectura Hexagonal', 72 | 'visible' => true, 73 | 'order' => 3, 74 | ], 75 | ], 76 | ]; 77 | 78 | public function handle(array $request): string 79 | { 80 | if (!isset($request['course_id'])) { 81 | return $this->jsonResponse(self::PATHS); 82 | } 83 | 84 | if (!isset(self::PATHS[$request['course_id']])) { 85 | return $this->jsonResponse([]); 86 | } 87 | 88 | return $this->jsonResponse(self::PATHS[$request['course_id']]); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /03-jwt/monolito/controller/CoursesGetController.php: -------------------------------------------------------------------------------- 1 | jsonResponse( 10 | [ 11 | [ 12 | 'id' => '77070', 13 | 'title' => 'Principios SOLID aplicados', 14 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FLfssR9kbRqyx2LaCMxp5%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=b387f292e2d8ac9cd4509923c3148971', 15 | 'url' => 'https://pro.codely.tv/library/principios-solid-aplicados/77070/about/', 16 | 'authors' => ['b4b9ee99-8290-4064-8e3c-e4fd925fe0b9', '39402ea6-d5a0-4466-918d-e5eef75cc8a9'], 17 | ], 18 | [ 19 | 'id' => '66748', 20 | 'title' => 'Arquitectura Hexagonal', 21 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FDYWJYE5RMC0bkd8nCp0u%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=20ec61abaa2b3bcb181b06d9cd5fa5da', 22 | 'url' => 'https://pro.codely.tv/library/arquitectura-hexagonal/66748/about/', 23 | 'authors' => ['b4b9ee99-8290-4064-8e3c-e4fd925fe0b9', '39402ea6-d5a0-4466-918d-e5eef75cc8a9'], 24 | ], 25 | [ 26 | 'id' => '90916', 27 | 'title' => 'Testing: Introducción y buenas prácticas', 28 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2Fb3pxykWKS8auYDKgo0fg%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=c0b219bd939f156a11ed42f3f5439852', 29 | 'url' => 'https://pro.codely.tv/library/testing-introduccion-y-buenas-practicas/90916/about/', 30 | 'authors' => ['b4b9ee99-8290-4064-8e3c-e4fd925fe0b9', '39402ea6-d5a0-4466-918d-e5eef75cc8a9'], 31 | ], 32 | [ 33 | 'id' => '87157', 34 | 'title' => 'Domain-Driven Design - DDD Aplicado', 35 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2F057B1vhnSuihianWMp0j%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=30bd263228ec0c543b2d66ec314d978d', 36 | 'url' => 'https://pro.codely.tv/library/domain-driven-design-ddd/87157/about/', 37 | 'authors' => ['b4b9ee99-8290-4064-8e3c-e4fd925fe0b9', '39402ea6-d5a0-4466-918d-e5eef75cc8a9'], 38 | ] 39 | ] 40 | ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /05-requests-and-responses/05.3-standarization/monolito/controller/AuthorsGetController.php: -------------------------------------------------------------------------------- 1 | 'b4b9ee99-8290-4064-8e3c-e4fd925fe0b9', 10 | 'name' => 'Javier Ferrer', 11 | 'avatar' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FCERdtqBcSWe4hKpoUeoz%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=1f5c7a1eda9180240c52901a24af43df', 12 | ], 13 | [ 14 | 'id' => '39402ea6-d5a0-4466-918d-e5eef75cc8a9', 15 | 'name' => 'Rafa Gómez', 16 | 'avatar' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FSkO7YnieTieDgWfev170%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=3a11c0499b9dc9f31168e1b0285fb664', 17 | ], 18 | [ 19 | 'id' => '6a8344bc-d527-4100-a83a-d2bb298fdbf7', 20 | 'name' => 'Jose Armesto', 21 | 'avatar' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2Fc9nWZL8TlquzsW6So1jV%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=9a6d348c3efd4df8f5076ff984f18d68', 22 | ], 23 | [ 24 | 'id' => '9ebe81d3-0dd6-48d2-9e3a-2d60fd348b29', 25 | 'name' => 'Ramón Aranda', 26 | 'avatar' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2F1v8Hwh0QgKLsQGBvzZ0h%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=e06740a20d79cdd416391d028daf3457', 27 | ], 28 | [ 29 | 'id' => 'ce4a0077-2062-49f9-aaeb-a09ac3888f31', 30 | 'name' => 'Jordi Llonch', 31 | 'avatar' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FzzKesprROSzkyK8iwAbn%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=0179a7c0e20f2e989393ddd2a95e5f80', 32 | ], 33 | ]; 34 | 35 | public function handle(array $request): string 36 | { 37 | return isset($request['course_id']) 38 | ? $this->authorsByCourse($request['course_id']) 39 | : $this->jsonResponse(self::ALL_AUTHORS); 40 | } 41 | 42 | private function authorsByCourse(string $courseId): string 43 | { 44 | if (!isset(CoursesGetController::ALL_COURSES[$courseId])) { 45 | $this->notFoundResponse("The course `$courseId` doesn't exist"); 46 | } 47 | 48 | return $this->jsonResponse(CoursesGetController::ALL_COURSES[$courseId]['authors']); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /06-migrating-product-page/06.1-mocking-response/monolito/controller/AuthorsGetController.php: -------------------------------------------------------------------------------- 1 | 'b4b9ee99-8290-4064-8e3c-e4fd925fe0b9', 10 | 'name' => 'Javier Ferrer', 11 | 'avatar' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FCERdtqBcSWe4hKpoUeoz%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=1f5c7a1eda9180240c52901a24af43df', 12 | ], 13 | [ 14 | 'id' => '39402ea6-d5a0-4466-918d-e5eef75cc8a9', 15 | 'name' => 'Rafa Gómez', 16 | 'avatar' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FSkO7YnieTieDgWfev170%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=3a11c0499b9dc9f31168e1b0285fb664', 17 | ], 18 | [ 19 | 'id' => '6a8344bc-d527-4100-a83a-d2bb298fdbf7', 20 | 'name' => 'Jose Armesto', 21 | 'avatar' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2Fc9nWZL8TlquzsW6So1jV%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=9a6d348c3efd4df8f5076ff984f18d68', 22 | ], 23 | [ 24 | 'id' => '9ebe81d3-0dd6-48d2-9e3a-2d60fd348b29', 25 | 'name' => 'Ramón Aranda', 26 | 'avatar' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2F1v8Hwh0QgKLsQGBvzZ0h%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=e06740a20d79cdd416391d028daf3457', 27 | ], 28 | [ 29 | 'id' => 'ce4a0077-2062-49f9-aaeb-a09ac3888f31', 30 | 'name' => 'Jordi Llonch', 31 | 'avatar' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FzzKesprROSzkyK8iwAbn%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=0179a7c0e20f2e989393ddd2a95e5f80', 32 | ], 33 | ]; 34 | 35 | public function handle(array $request): string 36 | { 37 | return isset($request['course_id']) 38 | ? $this->authorsByCourse($request['course_id']) 39 | : $this->jsonResponse(self::ALL_AUTHORS); 40 | } 41 | 42 | private function authorsByCourse(string $courseId): string 43 | { 44 | if (!isset(CoursesGetController::ALL_COURSES[$courseId])) { 45 | $this->notFoundResponse("The course `$courseId` doesn't exist"); 46 | } 47 | 48 | return $this->jsonResponse(CoursesGetController::ALL_COURSES[$courseId]['authors']); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /06-migrating-product-page/06.2-order-petitions/monolito/controller/AuthorsGetController.php: -------------------------------------------------------------------------------- 1 | 'b4b9ee99-8290-4064-8e3c-e4fd925fe0b9', 10 | 'name' => 'Javier Ferrer', 11 | 'avatar' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FCERdtqBcSWe4hKpoUeoz%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=1f5c7a1eda9180240c52901a24af43df', 12 | ], 13 | [ 14 | 'id' => '39402ea6-d5a0-4466-918d-e5eef75cc8a9', 15 | 'name' => 'Rafa Gómez', 16 | 'avatar' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FSkO7YnieTieDgWfev170%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=3a11c0499b9dc9f31168e1b0285fb664', 17 | ], 18 | [ 19 | 'id' => '6a8344bc-d527-4100-a83a-d2bb298fdbf7', 20 | 'name' => 'Jose Armesto', 21 | 'avatar' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2Fc9nWZL8TlquzsW6So1jV%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=9a6d348c3efd4df8f5076ff984f18d68', 22 | ], 23 | [ 24 | 'id' => '9ebe81d3-0dd6-48d2-9e3a-2d60fd348b29', 25 | 'name' => 'Ramón Aranda', 26 | 'avatar' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2F1v8Hwh0QgKLsQGBvzZ0h%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=e06740a20d79cdd416391d028daf3457', 27 | ], 28 | [ 29 | 'id' => 'ce4a0077-2062-49f9-aaeb-a09ac3888f31', 30 | 'name' => 'Jordi Llonch', 31 | 'avatar' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FzzKesprROSzkyK8iwAbn%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=0179a7c0e20f2e989393ddd2a95e5f80', 32 | ], 33 | ]; 34 | 35 | public function handle(array $request): string 36 | { 37 | return isset($request['course_id']) 38 | ? $this->authorsByCourse($request['course_id']) 39 | : $this->jsonResponse(self::ALL_AUTHORS); 40 | } 41 | 42 | private function authorsByCourse(string $courseId): string 43 | { 44 | if (!isset(CoursesGetController::ALL_COURSES[$courseId])) { 45 | $this->notFoundResponse("The course `$courseId` doesn't exist"); 46 | } 47 | 48 | return $this->jsonResponse(CoursesGetController::ALL_COURSES[$courseId]['authors']); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /04-auth-microservice/monolito/controller/CoursesGetController.php: -------------------------------------------------------------------------------- 1 | jsonResponse( 10 | [ 11 | [ 12 | 'id' => '77070', 13 | 'title' => 'Principios SOLID aplicados', 14 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FLfssR9kbRqyx2LaCMxp5%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=b387f292e2d8ac9cd4509923c3148971', 15 | 'url' => 'https://pro.codely.tv/library/principios-solid-aplicados/77070/about/', 16 | 'authors' => ['b4b9ee99-8290-4064-8e3c-e4fd925fe0b9', '39402ea6-d5a0-4466-918d-e5eef75cc8a9'], 17 | ], 18 | [ 19 | 'id' => '66748', 20 | 'title' => 'Arquitectura Hexagonal', 21 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FDYWJYE5RMC0bkd8nCp0u%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=20ec61abaa2b3bcb181b06d9cd5fa5da', 22 | 'url' => 'https://pro.codely.tv/library/arquitectura-hexagonal/66748/about/', 23 | 'authors' => ['b4b9ee99-8290-4064-8e3c-e4fd925fe0b9', '39402ea6-d5a0-4466-918d-e5eef75cc8a9'], 24 | ], 25 | [ 26 | 'id' => '90916', 27 | 'title' => 'Testing: Introducción y buenas prácticas', 28 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2Fb3pxykWKS8auYDKgo0fg%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=c0b219bd939f156a11ed42f3f5439852', 29 | 'url' => 'https://pro.codely.tv/library/testing-introduccion-y-buenas-practicas/90916/about/', 30 | 'authors' => ['b4b9ee99-8290-4064-8e3c-e4fd925fe0b9', '39402ea6-d5a0-4466-918d-e5eef75cc8a9'], 31 | ], 32 | [ 33 | 'id' => '87157', 34 | 'title' => 'Domain-Driven Design - DDD Aplicado', 35 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2F057B1vhnSuihianWMp0j%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=30bd263228ec0c543b2d66ec314d978d', 36 | 'url' => 'https://pro.codely.tv/library/domain-driven-design-ddd/87157/about/', 37 | 'authors' => ['b4b9ee99-8290-4064-8e3c-e4fd925fe0b9', '39402ea6-d5a0-4466-918d-e5eef75cc8a9'], 38 | ] 39 | ] 40 | ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /05-requests-and-responses/05.2-serializing/monolito/controller/AuthorsGetController.php: -------------------------------------------------------------------------------- 1 | 'b4b9ee99-8290-4064-8e3c-e4fd925fe0b9', 10 | 'name' => 'Javier Ferrer', 11 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FCERdtqBcSWe4hKpoUeoz%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=1f5c7a1eda9180240c52901a24af43df', 12 | ], 13 | [ 14 | 'id' => '39402ea6-d5a0-4466-918d-e5eef75cc8a9', 15 | 'name' => 'Rafa Gómez', 16 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FSkO7YnieTieDgWfev170%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=3a11c0499b9dc9f31168e1b0285fb664', 17 | ], 18 | [ 19 | 'id' => '6a8344bc-d527-4100-a83a-d2bb298fdbf7', 20 | 'name' => 'Jose Armesto', 21 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2Fc9nWZL8TlquzsW6So1jV%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=9a6d348c3efd4df8f5076ff984f18d68', 22 | ], 23 | [ 24 | 'id' => '9ebe81d3-0dd6-48d2-9e3a-2d60fd348b29', 25 | 'name' => 'Ramón Aranda', 26 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2F1v8Hwh0QgKLsQGBvzZ0h%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=e06740a20d79cdd416391d028daf3457', 27 | ], 28 | [ 29 | 'id' => 'ce4a0077-2062-49f9-aaeb-a09ac3888f31', 30 | 'name' => 'Jordi Llonch', 31 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FzzKesprROSzkyK8iwAbn%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=0179a7c0e20f2e989393ddd2a95e5f80', 32 | ], 33 | ]; 34 | 35 | public function handle(array $request): string 36 | { 37 | return isset($request['course_id']) 38 | ? $this->authorsByCourse($request['course_id']) 39 | : $this->jsonResponse(self::ALL_AUTHORS); 40 | } 41 | 42 | private function authorsByCourse(string $courseId): string 43 | { 44 | if (! isset(CoursesGetController::ALL_COURSES[$courseId])) { 45 | $this->notFoundResponse("The course `$courseId` doesn't exist"); 46 | } 47 | 48 | return $this->jsonResponse(CoursesGetController::ALL_COURSES[$courseId]['authors']); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /05-requests-and-responses/05.1-splitting-in-multiples-endpoints/monolito/controller/AuthorsGetController.php: -------------------------------------------------------------------------------- 1 | 'b4b9ee99-8290-4064-8e3c-e4fd925fe0b9', 10 | 'name' => 'Javier Ferrer', 11 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FCERdtqBcSWe4hKpoUeoz%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=1f5c7a1eda9180240c52901a24af43df', 12 | ], 13 | [ 14 | 'id' => '39402ea6-d5a0-4466-918d-e5eef75cc8a9', 15 | 'name' => 'Rafa Gómez', 16 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FSkO7YnieTieDgWfev170%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=3a11c0499b9dc9f31168e1b0285fb664', 17 | ], 18 | [ 19 | 'id' => '6a8344bc-d527-4100-a83a-d2bb298fdbf7', 20 | 'name' => 'Jose Armesto', 21 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2Fc9nWZL8TlquzsW6So1jV%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=9a6d348c3efd4df8f5076ff984f18d68', 22 | ], 23 | [ 24 | 'id' => '9ebe81d3-0dd6-48d2-9e3a-2d60fd348b29', 25 | 'name' => 'Ramón Aranda', 26 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2F1v8Hwh0QgKLsQGBvzZ0h%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=e06740a20d79cdd416391d028daf3457', 27 | ], 28 | [ 29 | 'id' => 'ce4a0077-2062-49f9-aaeb-a09ac3888f31', 30 | 'name' => 'Jordi Llonch', 31 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FzzKesprROSzkyK8iwAbn%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=0179a7c0e20f2e989393ddd2a95e5f80', 32 | ], 33 | ]; 34 | 35 | public function handle(array $request): string 36 | { 37 | return isset($request['course_id']) 38 | ? $this->authorsByCourse($request['course_id']) 39 | : $this->jsonResponse(self::ALL_AUTHORS); 40 | } 41 | 42 | private function authorsByCourse(string $courseId): string 43 | { 44 | if (! isset(CoursesGetController::ALL_COURSES[$courseId])) { 45 | $this->notFoundResponse("The course `$courseId` doesn't exist"); 46 | } 47 | 48 | return $this->jsonResponse(CoursesGetController::ALL_COURSES[$courseId]['authors']); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /05-requests-and-responses/05.2-serializing/monolito/controller/CoursesGetController.php: -------------------------------------------------------------------------------- 1 | [ 9 | 'id' => '77070', 10 | 'title' => 'Principios SOLID aplicados', 11 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FLfssR9kbRqyx2LaCMxp5%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=b387f292e2d8ac9cd4509923c3148971', 12 | 'url' => 'https://pro.codely.tv/library/principios-solid-aplicados/77070/about/', 13 | 'authors' => ['b4b9ee99-8290-4064-8e3c-e4fd925fe0b9', '39402ea6-d5a0-4466-918d-e5eef75cc8a9'], 14 | ], 15 | 66748 => [ 16 | 'id' => '66748', 17 | 'title' => 'Arquitectura Hexagonal', 18 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FDYWJYE5RMC0bkd8nCp0u%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=20ec61abaa2b3bcb181b06d9cd5fa5da', 19 | 'url' => 'https://pro.codely.tv/library/arquitectura-hexagonal/66748/about/', 20 | 'authors' => ['b4b9ee99-8290-4064-8e3c-e4fd925fe0b9', '39402ea6-d5a0-4466-918d-e5eef75cc8a9'], 21 | ], 22 | 90916 => [ 23 | 'id' => '90916', 24 | 'title' => 'Testing: Introducción y buenas prácticas', 25 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2Fb3pxykWKS8auYDKgo0fg%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=c0b219bd939f156a11ed42f3f5439852', 26 | 'url' => 'https://pro.codely.tv/library/testing-introduccion-y-buenas-practicas/90916/about/', 27 | 'authors' => ['b4b9ee99-8290-4064-8e3c-e4fd925fe0b9', '39402ea6-d5a0-4466-918d-e5eef75cc8a9'], 28 | ], 29 | 87157 => [ 30 | 'id' => '87157', 31 | 'title' => 'Domain-Driven Design - DDD Aplicado', 32 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2F057B1vhnSuihianWMp0j%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=30bd263228ec0c543b2d66ec314d978d', 33 | 'url' => 'https://pro.codely.tv/library/domain-driven-design-ddd/87157/about/', 34 | 'authors' => ['b4b9ee99-8290-4064-8e3c-e4fd925fe0b9', '39402ea6-d5a0-4466-918d-e5eef75cc8a9'], 35 | ], 36 | ]; 37 | 38 | public function handle(array $request): string 39 | { 40 | return $this->hasResourceId($request) 41 | ? $this->specificCourse($this->resourceId($request)) 42 | : $this->jsonResponse(array_values(self::ALL_COURSES)); 43 | } 44 | 45 | public function specificCourse(string $courseId): string 46 | { 47 | return isset(self::ALL_COURSES[$courseId]) 48 | ? $this->jsonResponse(self::ALL_COURSES[$courseId]) 49 | : $this->notFoundResponse("The course `$courseId` doesn't exist"); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /05-requests-and-responses/05.3-standarization/monolito/controller/CoursesGetController.php: -------------------------------------------------------------------------------- 1 | [ 9 | 'id' => '77070', 10 | 'title' => 'Principios SOLID aplicados', 11 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FLfssR9kbRqyx2LaCMxp5%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=b387f292e2d8ac9cd4509923c3148971', 12 | 'url' => 'https://pro.codely.tv/library/principios-solid-aplicados/77070/about/', 13 | 'authors' => ['b4b9ee99-8290-4064-8e3c-e4fd925fe0b9', '39402ea6-d5a0-4466-918d-e5eef75cc8a9'], 14 | ], 15 | 66748 => [ 16 | 'id' => '66748', 17 | 'title' => 'Arquitectura Hexagonal', 18 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FDYWJYE5RMC0bkd8nCp0u%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=20ec61abaa2b3bcb181b06d9cd5fa5da', 19 | 'url' => 'https://pro.codely.tv/library/arquitectura-hexagonal/66748/about/', 20 | 'authors' => ['b4b9ee99-8290-4064-8e3c-e4fd925fe0b9', '39402ea6-d5a0-4466-918d-e5eef75cc8a9'], 21 | ], 22 | 90916 => [ 23 | 'id' => '90916', 24 | 'title' => 'Testing: Introducción y buenas prácticas', 25 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2Fb3pxykWKS8auYDKgo0fg%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=c0b219bd939f156a11ed42f3f5439852', 26 | 'url' => 'https://pro.codely.tv/library/testing-introduccion-y-buenas-practicas/90916/about/', 27 | 'authors' => ['b4b9ee99-8290-4064-8e3c-e4fd925fe0b9', '39402ea6-d5a0-4466-918d-e5eef75cc8a9'], 28 | ], 29 | 87157 => [ 30 | 'id' => '87157', 31 | 'title' => 'Domain-Driven Design - DDD Aplicado', 32 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2F057B1vhnSuihianWMp0j%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=30bd263228ec0c543b2d66ec314d978d', 33 | 'url' => 'https://pro.codely.tv/library/domain-driven-design-ddd/87157/about/', 34 | 'authors' => ['b4b9ee99-8290-4064-8e3c-e4fd925fe0b9', '39402ea6-d5a0-4466-918d-e5eef75cc8a9'], 35 | ], 36 | ]; 37 | 38 | public function handle(array $request): string 39 | { 40 | return $this->hasResourceId($request) 41 | ? $this->specificCourse($this->resourceId($request)) 42 | : $this->jsonResponse(array_values(self::ALL_COURSES)); 43 | } 44 | 45 | public function specificCourse(string $courseId): string 46 | { 47 | return isset(self::ALL_COURSES[$courseId]) 48 | ? $this->jsonResponse(self::ALL_COURSES[$courseId]) 49 | : $this->notFoundResponse("The course `$courseId` doesn't exist"); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /06-migrating-product-page/06.1-mocking-response/monolito/controller/CoursesGetController.php: -------------------------------------------------------------------------------- 1 | [ 9 | 'id' => '77070', 10 | 'title' => 'Principios SOLID aplicados', 11 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FLfssR9kbRqyx2LaCMxp5%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=b387f292e2d8ac9cd4509923c3148971', 12 | 'url' => 'https://pro.codely.tv/library/principios-solid-aplicados/77070/about/', 13 | 'authors' => ['b4b9ee99-8290-4064-8e3c-e4fd925fe0b9', '39402ea6-d5a0-4466-918d-e5eef75cc8a9'], 14 | ], 15 | 66748 => [ 16 | 'id' => '66748', 17 | 'title' => 'Arquitectura Hexagonal', 18 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FDYWJYE5RMC0bkd8nCp0u%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=20ec61abaa2b3bcb181b06d9cd5fa5da', 19 | 'url' => 'https://pro.codely.tv/library/arquitectura-hexagonal/66748/about/', 20 | 'authors' => ['b4b9ee99-8290-4064-8e3c-e4fd925fe0b9', '39402ea6-d5a0-4466-918d-e5eef75cc8a9'], 21 | ], 22 | 90916 => [ 23 | 'id' => '90916', 24 | 'title' => 'Testing: Introducción y buenas prácticas', 25 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2Fb3pxykWKS8auYDKgo0fg%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=c0b219bd939f156a11ed42f3f5439852', 26 | 'url' => 'https://pro.codely.tv/library/testing-introduccion-y-buenas-practicas/90916/about/', 27 | 'authors' => ['b4b9ee99-8290-4064-8e3c-e4fd925fe0b9', '39402ea6-d5a0-4466-918d-e5eef75cc8a9'], 28 | ], 29 | 87157 => [ 30 | 'id' => '87157', 31 | 'title' => 'Domain-Driven Design - DDD Aplicado', 32 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2F057B1vhnSuihianWMp0j%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=30bd263228ec0c543b2d66ec314d978d', 33 | 'url' => 'https://pro.codely.tv/library/domain-driven-design-ddd/87157/about/', 34 | 'authors' => ['b4b9ee99-8290-4064-8e3c-e4fd925fe0b9', '39402ea6-d5a0-4466-918d-e5eef75cc8a9'], 35 | ], 36 | ]; 37 | 38 | public function handle(array $request): string 39 | { 40 | return $this->hasResourceId($request) 41 | ? $this->specificCourse($this->resourceId($request)) 42 | : $this->jsonResponse(array_values(self::ALL_COURSES)); 43 | } 44 | 45 | public function specificCourse(string $courseId): string 46 | { 47 | return isset(self::ALL_COURSES[$courseId]) 48 | ? $this->jsonResponse(self::ALL_COURSES[$courseId]) 49 | : $this->notFoundResponse("The course `$courseId` doesn't exist"); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /05-requests-and-responses/05.1-splitting-in-multiples-endpoints/monolito/controller/CoursesGetController.php: -------------------------------------------------------------------------------- 1 | [ 9 | 'id' => '77070', 10 | 'title' => 'Principios SOLID aplicados', 11 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FLfssR9kbRqyx2LaCMxp5%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=b387f292e2d8ac9cd4509923c3148971', 12 | 'url' => 'https://pro.codely.tv/library/principios-solid-aplicados/77070/about/', 13 | 'authors' => ['b4b9ee99-8290-4064-8e3c-e4fd925fe0b9', '39402ea6-d5a0-4466-918d-e5eef75cc8a9'], 14 | ], 15 | 66748 => [ 16 | 'id' => '66748', 17 | 'title' => 'Arquitectura Hexagonal', 18 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FDYWJYE5RMC0bkd8nCp0u%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=20ec61abaa2b3bcb181b06d9cd5fa5da', 19 | 'url' => 'https://pro.codely.tv/library/arquitectura-hexagonal/66748/about/', 20 | 'authors' => ['b4b9ee99-8290-4064-8e3c-e4fd925fe0b9', '39402ea6-d5a0-4466-918d-e5eef75cc8a9'], 21 | ], 22 | 90916 => [ 23 | 'id' => '90916', 24 | 'title' => 'Testing: Introducción y buenas prácticas', 25 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2Fb3pxykWKS8auYDKgo0fg%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=c0b219bd939f156a11ed42f3f5439852', 26 | 'url' => 'https://pro.codely.tv/library/testing-introduccion-y-buenas-practicas/90916/about/', 27 | 'authors' => ['b4b9ee99-8290-4064-8e3c-e4fd925fe0b9', '39402ea6-d5a0-4466-918d-e5eef75cc8a9'], 28 | ], 29 | 87157 => [ 30 | 'id' => '87157', 31 | 'title' => 'Domain-Driven Design - DDD Aplicado', 32 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2F057B1vhnSuihianWMp0j%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=30bd263228ec0c543b2d66ec314d978d', 33 | 'url' => 'https://pro.codely.tv/library/domain-driven-design-ddd/87157/about/', 34 | 'authors' => ['b4b9ee99-8290-4064-8e3c-e4fd925fe0b9', '39402ea6-d5a0-4466-918d-e5eef75cc8a9'], 35 | ], 36 | ]; 37 | 38 | public function handle(array $request): string 39 | { 40 | return $this->hasResourceId($request) 41 | ? $this->specificCourse($this->resourceId($request)) 42 | : $this->jsonResponse(array_values(self::ALL_COURSES)); 43 | } 44 | 45 | public function specificCourse(string $courseId): string 46 | { 47 | return isset(self::ALL_COURSES[$courseId]) 48 | ? $this->jsonResponse(self::ALL_COURSES[$courseId]) 49 | : $this->notFoundResponse("The course `$courseId` doesn't exist"); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /06-migrating-product-page/06.2-order-petitions/monolito/controller/CoursesGetController.php: -------------------------------------------------------------------------------- 1 | [ 9 | 'id' => '77070', 10 | 'title' => 'Principios SOLID aplicados', 11 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FLfssR9kbRqyx2LaCMxp5%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=b387f292e2d8ac9cd4509923c3148971', 12 | 'url' => 'https://pro.codely.tv/library/principios-solid-aplicados/77070/about/', 13 | 'authors' => ['b4b9ee99-8290-4064-8e3c-e4fd925fe0b9', '39402ea6-d5a0-4466-918d-e5eef75cc8a9'], 14 | 'price_plan_id' => '4c5be45d-799b-49c5-93bc-859a832a2a65', 15 | ], 16 | 66748 => [ 17 | 'id' => '66748', 18 | 'title' => 'Arquitectura Hexagonal', 19 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FDYWJYE5RMC0bkd8nCp0u%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=20ec61abaa2b3bcb181b06d9cd5fa5da', 20 | 'url' => 'https://pro.codely.tv/library/arquitectura-hexagonal/66748/about/', 21 | 'authors' => ['b4b9ee99-8290-4064-8e3c-e4fd925fe0b9', '39402ea6-d5a0-4466-918d-e5eef75cc8a9'], 22 | 'price_plan_id' => '4c5be45d-799b-49c5-93bc-859a832a2a65', 23 | ], 24 | 90916 => [ 25 | 'id' => '90916', 26 | 'title' => 'Testing: Introducción y buenas prácticas', 27 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2Fb3pxykWKS8auYDKgo0fg%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=c0b219bd939f156a11ed42f3f5439852', 28 | 'url' => 'https://pro.codely.tv/library/testing-introduccion-y-buenas-practicas/90916/about/', 29 | 'authors' => ['b4b9ee99-8290-4064-8e3c-e4fd925fe0b9', '39402ea6-d5a0-4466-918d-e5eef75cc8a9'], 30 | 'price_plan_id' => '4c5be45d-799b-49c5-93bc-859a832a2a65', 31 | ], 32 | 87157 => [ 33 | 'id' => '87157', 34 | 'title' => 'Domain-Driven Design - DDD Aplicado', 35 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2F057B1vhnSuihianWMp0j%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=30bd263228ec0c543b2d66ec314d978d', 36 | 'url' => 'https://pro.codely.tv/library/domain-driven-design-ddd/87157/about/', 37 | 'authors' => ['b4b9ee99-8290-4064-8e3c-e4fd925fe0b9', '39402ea6-d5a0-4466-918d-e5eef75cc8a9'], 38 | 'price_plan_id' => 'f1f62b61-e123-434f-99ff-4c64d7f34f3b', 39 | ], 40 | ]; 41 | 42 | public function handle(array $request): string 43 | { 44 | return $this->hasResourceId($request) 45 | ? $this->specificCourse($this->resourceId($request)) 46 | : $this->jsonResponse(array_values(self::ALL_COURSES)); 47 | } 48 | 49 | public function specificCourse(string $courseId): string 50 | { 51 | return isset(self::ALL_COURSES[$courseId]) 52 | ? $this->jsonResponse(self::ALL_COURSES[$courseId]) 53 | : $this->notFoundResponse("The course `$courseId` doesn't exist"); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /01-monolith/controller/CoursesGetController.php: -------------------------------------------------------------------------------- 1 | [ 9 | 'name' => 'Javier Ferrer', 10 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FCERdtqBcSWe4hKpoUeoz%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=1f5c7a1eda9180240c52901a24af43df', 11 | ], 12 | '39402ea6-d5a0-4466-918d-e5eef75cc8a9' => [ 13 | 'name' => 'Rafa Gómez', 14 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FSkO7YnieTieDgWfev170%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=3a11c0499b9dc9f31168e1b0285fb664', 15 | ], 16 | '6a8344bc-d527-4100-a83a-d2bb298fdbf7' => [ 17 | 'name' => 'Jose Armesto', 18 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2Fc9nWZL8TlquzsW6So1jV%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=9a6d348c3efd4df8f5076ff984f18d68', 19 | ], 20 | '9ebe81d3-0dd6-48d2-9e3a-2d60fd348b29' => [ 21 | 'name' => 'Ramón Aranda', 22 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2F1v8Hwh0QgKLsQGBvzZ0h%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=e06740a20d79cdd416391d028daf3457', 23 | ], 24 | 'ce4a0077-2062-49f9-aaeb-a09ac3888f31' => [ 25 | 'name' => 'Jordi Llonch', 26 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FzzKesprROSzkyK8iwAbn%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?crop=faces&fit=crop&h=250&ixlib=python-1.1.0&w=250&s=0179a7c0e20f2e989393ddd2a95e5f80', 27 | ], 28 | ]; 29 | 30 | private const COURSES = [ 31 | '77070' => [ 32 | 'title' => 'Principios SOLID aplicados', 33 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FLfssR9kbRqyx2LaCMxp5%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=b387f292e2d8ac9cd4509923c3148971', 34 | 'url' => 'https://pro.codely.tv/library/principios-solid-aplicados/77070/about/', 35 | 'authors' => [ 36 | self::AUTHORS['b4b9ee99-8290-4064-8e3c-e4fd925fe0b9'], 37 | self::AUTHORS['39402ea6-d5a0-4466-918d-e5eef75cc8a9'], 38 | ], 39 | 'path' => [ 40 | [ 41 | 'title' => 'Qué son los principios SOLID (Huyendo de STUPID) 🦄 - ¡Disponible sin registro! 💸', 42 | 'visible' => true, 43 | 'order' => 1, 44 | ], 45 | [ 46 | 'title' => 'UML, ese gran denostado 🤕', 47 | 'visible' => true, 48 | 'order' => 2, 49 | ], 50 | [ 51 | 'title' => 'Principio de Responsabilidad Única 🕺', 52 | 'visible' => true, 53 | 'order' => 3, 54 | ], 55 | ] 56 | ], 57 | '66748' => [ 58 | 'title' => 'Arquitectura Hexagonal', 59 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2FDYWJYE5RMC0bkd8nCp0u%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=20ec61abaa2b3bcb181b06d9cd5fa5da', 60 | 'url' => 'https://pro.codely.tv/library/arquitectura-hexagonal/66748/about/', 61 | 'authors' => [ 62 | self::AUTHORS['b4b9ee99-8290-4064-8e3c-e4fd925fe0b9'], 63 | self::AUTHORS['39402ea6-d5a0-4466-918d-e5eef75cc8a9'], 64 | ], 65 | 'path' => [ 66 | [ 67 | 'title' => 'Bienvenida al curso 👋 ¡Disponible sin registro! 💸', 68 | 'visible' => true, 69 | 'order' => 1, 70 | ], 71 | [ 72 | 'title' => 'Qué es la Arquitectura de Software 💎', 73 | 'visible' => true, 74 | 'order' => 2, 75 | ], 76 | [ 77 | 'title' => 'Qué es la Arquitectura Hexagonal ⬢', 78 | 'visible' => true, 79 | 'order' => 3, 80 | ], 81 | ] 82 | ], 83 | '90916' => [ 84 | 'title' => 'Testing: Introducción y buenas prácticas', 85 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2Fb3pxykWKS8auYDKgo0fg%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=c0b219bd939f156a11ed42f3f5439852', 86 | 'url' => 'https://pro.codely.tv/library/testing-introduccion-y-buenas-practicas/90916/about/', 87 | 'authors' => [ 88 | self::AUTHORS['b4b9ee99-8290-4064-8e3c-e4fd925fe0b9'], 89 | self::AUTHORS['39402ea6-d5a0-4466-918d-e5eef75cc8a9'], 90 | ], 91 | 'path' => [ 92 | [ 93 | 'title' => '🤔 ¿Qué es el testing y qué aporta? ¿Por qué deberíamos testear? - Disponible sin registro', 94 | 'visible' => true, 95 | 'order' => 1, 96 | ], 97 | [ 98 | 'title' => '🚀 ¡Al turrón!: Nuestros primeros tests', 99 | 'visible' => true, 100 | 'order' => 2, 101 | ], 102 | [ 103 | 'title' => '🌀 Exprimiendo nuestro framework de testing (PHP, Java, JavaScript, y Scala)', 104 | 'visible' => true, 105 | 'order' => 3, 106 | ], 107 | ] 108 | ], 109 | '87157' => [ 110 | 'title' => 'Domain-Driven Design - DDD Aplicado', 111 | 'thumbnail' => 'https://pathwright.imgix.net/https%3A%2F%2Fcdn.filestackcontent.com%2Fapi%2Ffile%2F057B1vhnSuihianWMp0j%3Fsignature%3D888b9ea3eb997a4d59215bfbe2983c636df3c7da0ff8c6f85811ff74c8982e34%26policy%3DeyJjYWxsIjogWyJyZWFkIiwgInN0YXQiLCAiY29udmVydCJdLCAiZXhwaXJ5IjogNDYyMDM3NzAzMX0%253D?dpr=2&fit=crop&h=232&ixlib=python-1.1.0&w=310&s=30bd263228ec0c543b2d66ec314d978d', 112 | 'url' => 'https://pro.codely.tv/library/domain-driven-design-ddd/87157/about/', 113 | 'authors' => [ 114 | self::AUTHORS['b4b9ee99-8290-4064-8e3c-e4fd925fe0b9'], 115 | self::AUTHORS['39402ea6-d5a0-4466-918d-e5eef75cc8a9'], 116 | ], 117 | 'path' => [ 118 | [ 119 | 'title' => '👋 DDD en 20 minutos - Disponible sin registro', 120 | 'visible' => true, 121 | 'order' => 1, 122 | ], 123 | [ 124 | 'title' => '🚀 Bounded Contexts, subdomains y modules: Creando nuestra aplicación', 125 | 'visible' => true, 126 | 'order' => 2, 127 | ], 128 | [ 129 | 'title' => '🎯 Arquitectura Hexagonal', 130 | 'visible' => true, 131 | 'order' => 3, 132 | ], 133 | ] 134 | ], 135 | ]; 136 | 137 | public function handle(array $request): string 138 | { 139 | if (!isset($request['course_id'])) { 140 | return $this->jsonResponse(self::COURSES); 141 | } 142 | 143 | if (!isset(self::COURSES[$request['course_id']])) { 144 | return $this->jsonResponse([]); 145 | } 146 | 147 | return $this->jsonResponse(self::COURSES[$request['course_id']]); 148 | } 149 | } 150 | --------------------------------------------------------------------------------