Skip to content

Commit 606de9e

Browse files
committed
Fix API routing and add Postman collection
1 parent 527bfdc commit 606de9e

File tree

6 files changed

+250
-51
lines changed

6 files changed

+250
-51
lines changed

app/core/Application.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ public function __construct()
2222
public function run()
2323
{
2424
$request = new Request();
25-
$response = $this->router->dispatch($request);
26-
$response->send();
25+
$this->router->dispatch($request);
2726
}
2827

2928
private function loadRoutes()

app/core/Response.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,10 @@ public function send()
3636
echo $this->body;
3737
exit;
3838
}
39+
40+
public static function json($data, $statusCode = 200)
41+
{
42+
$response = new self();
43+
return $response->setStatusCode($statusCode)->withJson($data);
44+
}
3945
}

app/core/Router.php

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,14 @@ class Router
1010

1111
public function addRoute($method, $uri, $handler, $middleware = [])
1212
{
13+
$fullUri = $uri;
14+
foreach ($this->routeGroups as $group) {
15+
$fullUri = $group['prefix'] . $fullUri;
16+
}
17+
1318
$this->routes[] = [
1419
'method' => $method,
15-
'uri' => $uri,
20+
'uri' => $fullUri,
1621
'handler' => $handler,
1722
'middleware' => $middleware
1823
];
@@ -35,7 +40,7 @@ private function resolveMiddleware(array $routeMiddleware): array
3540
return $middlewares;
3641
}
3742

38-
public function dispatch(Request $request, Response $response)
43+
public function dispatch(Request $request)
3944
{
4045
$requestUri = $request->getUri();
4146
$requestMethod = $request->getMethod();
@@ -48,20 +53,21 @@ public function dispatch(Request $request, Response $response)
4853
$handler = $route['handler'];
4954
$middleware = $this->resolveMiddleware($route['middleware']);
5055

51-
$this->runMiddleware($request, $response, $middleware, function (Request $request) use ($handler, $matches, $response) {
56+
$this->runMiddleware($request, $middleware, function (Request $request) use ($handler, $matches) {
5257
if (is_callable($handler)) {
53-
call_user_func_array($handler, array_merge([$request, $response], $matches));
58+
$response = call_user_func_array($handler, array_merge([$request], $matches));
5459
} elseif (is_array($handler) && count($handler) === 2) {
5560
list($controllerName, $methodName) = $handler;
5661
$controller = new $controllerName();
57-
call_user_func_array([$controller, $methodName], array_merge([$request, $response], $matches));
62+
$response = call_user_func_array([$controller, $methodName], array_merge([$request], $matches));
5863
}
64+
if ($response) $response->send();
5965
});
6066
return;
6167
}
6268
}
6369

64-
Response::json(['status' => 'error', 'message' => 'Not Found'], 404);
70+
Response::json(['status' => 'error', 'message' => 'Not Found'], 404)->send();
6571
}
6672

6773
private function buildRegexPattern(string $uri): string
@@ -71,11 +77,11 @@ private function buildRegexPattern(string $uri): string
7177
return "#^" . $pattern . "$#";
7278
}
7379

74-
private function runMiddleware(Request $request, Response $response, array $middleware, callable $coreHandler)
80+
private function runMiddleware(Request $request, array $middleware, callable $coreHandler)
7581
{
7682
$chain = array_reverse($middleware);
7783

78-
$next = function (Request $req) use (&$chain, $response, $coreHandler) {
84+
$next = function (Request $req) use (&$chain, $coreHandler) {
7985
if (empty($chain)) {
8086
return $coreHandler($req);
8187
}

app/routes/api.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@
22

33
use App\Core\Router;
44
use App\Controllers\UserController;
5+
use App\Controllers\HealthController;
56
use App\Middleware\AuthMiddleware;
67
use App\Middleware\CorsMiddleware;
78

89
/** @var Router $router */
910

1011
$router->group('/api', [CorsMiddleware::class], function (Router $router) {
1112
// Public routes
13+
$router->addRoute('GET', '/health', [HealthController::class, 'check']);
14+
$router->addRoute('GET', '/health/info', [HealthController::class, 'info']);
1215
$router->addRoute('POST', '/register', [UserController::class, 'register']);
1316
$router->addRoute('POST', '/login', [UserController::class, 'login']);
1417

docs/postman.json

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
{
2+
"info": {
3+
"name": "PHP REST API Pro Kit",
4+
"description": "A production-ready Raw PHP REST API Starter Kit with JWT authentication, user management, file uploads, caching, rate limiting, and Docker support.",
5+
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
6+
},
7+
"variable": [
8+
{
9+
"key": "baseUrl",
10+
"value": "http://localhost:8000",
11+
"type": "string"
12+
},
13+
{
14+
"key": "token",
15+
"value": "",
16+
"type": "string"
17+
}
18+
],
19+
"item": [
20+
{
21+
"name": "Health",
22+
"item": [
23+
{
24+
"name": "Health Check",
25+
"request": {
26+
"method": "GET",
27+
"header": [],
28+
"url": {
29+
"raw": "{{baseUrl}}/api/health",
30+
"host": ["{{baseUrl}}"],
31+
"path": ["api", "health"]
32+
}
33+
}
34+
},
35+
{
36+
"name": "System Info",
37+
"request": {
38+
"method": "GET",
39+
"header": [],
40+
"url": {
41+
"raw": "{{baseUrl}}/api/health/info",
42+
"host": ["{{baseUrl}}"],
43+
"path": ["api", "health", "info"]
44+
}
45+
}
46+
}
47+
]
48+
},
49+
{
50+
"name": "Authentication",
51+
"item": [
52+
{
53+
"name": "Register",
54+
"request": {
55+
"method": "POST",
56+
"header": [
57+
{
58+
"key": "Content-Type",
59+
"value": "application/json"
60+
}
61+
],
62+
"body": {
63+
"mode": "raw",
64+
"raw": "{\n \"name\": \"John Doe\",\n \"email\": \"john@example.com\",\n \"password\": \"password123\"\n}"
65+
},
66+
"url": {
67+
"raw": "{{baseUrl}}/api/register",
68+
"host": ["{{baseUrl}}"],
69+
"path": ["api", "register"]
70+
}
71+
}
72+
},
73+
{
74+
"name": "Login",
75+
"event": [
76+
{
77+
"listen": "test",
78+
"script": {
79+
"exec": [
80+
"if (pm.response.code === 200) {",
81+
" const response = pm.response.json();",
82+
" if (response.token) {",
83+
" pm.collectionVariables.set('token', response.token);",
84+
" }",
85+
"}"
86+
]
87+
}
88+
}
89+
],
90+
"request": {
91+
"method": "POST",
92+
"header": [
93+
{
94+
"key": "Content-Type",
95+
"value": "application/json"
96+
}
97+
],
98+
"body": {
99+
"mode": "raw",
100+
"raw": "{\n \"email\": \"admin@hrms.com\",\n \"password\": \"admin123\"\n}"
101+
},
102+
"url": {
103+
"raw": "{{baseUrl}}/api/login",
104+
"host": ["{{baseUrl}}"],
105+
"path": ["api", "login"]
106+
}
107+
}
108+
}
109+
]
110+
},
111+
{
112+
"name": "Users",
113+
"item": [
114+
{
115+
"name": "Get All Users",
116+
"request": {
117+
"method": "GET",
118+
"header": [
119+
{
120+
"key": "Authorization",
121+
"value": "Bearer {{token}}"
122+
}
123+
],
124+
"url": {
125+
"raw": "{{baseUrl}}/api/users",
126+
"host": ["{{baseUrl}}"],
127+
"path": ["api", "users"]
128+
}
129+
}
130+
},
131+
{
132+
"name": "Get User by ID",
133+
"request": {
134+
"method": "GET",
135+
"header": [
136+
{
137+
"key": "Authorization",
138+
"value": "Bearer {{token}}"
139+
}
140+
],
141+
"url": {
142+
"raw": "{{baseUrl}}/api/users/1",
143+
"host": ["{{baseUrl}}"],
144+
"path": ["api", "users", "1"]
145+
}
146+
}
147+
},
148+
{
149+
"name": "Create User",
150+
"request": {
151+
"method": "POST",
152+
"header": [
153+
{
154+
"key": "Authorization",
155+
"value": "Bearer {{token}}"
156+
},
157+
{
158+
"key": "Content-Type",
159+
"value": "application/json"
160+
}
161+
],
162+
"body": {
163+
"mode": "raw",
164+
"raw": "{\n \"name\": \"Jane Smith\",\n \"email\": \"jane@example.com\",\n \"password\": \"password123\"\n}"
165+
},
166+
"url": {
167+
"raw": "{{baseUrl}}/api/users",
168+
"host": ["{{baseUrl}}"],
169+
"path": ["api", "users"]
170+
}
171+
}
172+
},
173+
{
174+
"name": "Update User",
175+
"request": {
176+
"method": "PUT",
177+
"header": [
178+
{
179+
"key": "Authorization",
180+
"value": "Bearer {{token}}"
181+
},
182+
{
183+
"key": "Content-Type",
184+
"value": "application/json"
185+
}
186+
],
187+
"body": {
188+
"mode": "raw",
189+
"raw": "{\n \"name\": \"Jane Doe Updated\",\n \"email\": \"jane.updated@example.com\"\n}"
190+
},
191+
"url": {
192+
"raw": "{{baseUrl}}/api/users/1",
193+
"host": ["{{baseUrl}}"],
194+
"path": ["api", "users", "1"]
195+
}
196+
}
197+
},
198+
{
199+
"name": "Delete User",
200+
"request": {
201+
"method": "DELETE",
202+
"header": [
203+
{
204+
"key": "Authorization",
205+
"value": "Bearer {{token}}"
206+
}
207+
],
208+
"url": {
209+
"raw": "{{baseUrl}}/api/users/1",
210+
"host": ["{{baseUrl}}"],
211+
"path": ["api", "users", "1"]
212+
}
213+
}
214+
}
215+
]
216+
}
217+
]
218+
}

public/index.php

Lines changed: 8 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,10 @@
11
<?php
22

3-
require_once __DIR__ . '/../vendor/autoload.php';
4-
5-
use App\Core\Autoloader;
6-
use App\Core\Request;
7-
use App\Core\Response;
8-
use App\Core\Router;
9-
use App\Config\Env;
10-
use App\Exceptions\Handler;
11-
use App\Helpers\JwtHelper;
12-
use App\Helpers\Logger;
13-
14-
// Load environment variables
15-
Env::load(__DIR__ . '/../.env');
16-
17-
// Set up error and exception handling
18-
$handler = new Handler();
19-
set_exception_handler([$handler, 'handle']);
20-
set_error_handler(function ($severity, $message, $file, $line) use ($handler) {
21-
if (!(error_reporting() & $severity)) {
22-
// This error code is not included in error_reporting
23-
return;
24-
}
25-
$handler->handle(new \ErrorException($message, 0, $severity, $file, $line));
26-
});
27-
28-
// Initialize Logger
29-
Logger::init();
30-
31-
// Initialize JWT Helper
32-
JwtHelper::init();
33-
34-
// Create Request and Response objects
35-
$request = new Request();
36-
$response = new Response();
37-
38-
// Include API routes
39-
$router = new Router();
40-
require_once __DIR__ . '/../app/routes/api.php';
41-
42-
// Dispatch the request
43-
$router->dispatch($request, $response);
3+
try {
4+
$app = require_once __DIR__ . '/../bootstrap/app.php';
5+
$app->run();
6+
} catch (Exception $e) {
7+
http_response_code(500);
8+
header('Content-Type: application/json');
9+
echo json_encode(['error' => 'Internal Server Error']);
10+
}

0 commit comments

Comments
 (0)