Compare commits
3 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
ff0b61c42f | 9 months ago |
|
|
e4fac4c6b4 | 9 months ago |
|
|
f9eb6c4095 | 9 months ago |
@ -0,0 +1,2 @@ |
|||||||
|
*~ |
||||||
|
node_modules/ |
||||||
@ -0,0 +1,109 @@ |
|||||||
|
# Common HTTP Headers in REST APIs |
||||||
|
|
||||||
|
## Request Headers |
||||||
|
|
||||||
|
| Header Name | Purpose | Example Value | |
||||||
|
|-----------------------|-------------------------------------------------------|-----------------------------------------------| |
||||||
|
| `Authorization` | Carries auth credentials (token, Basic, Bearer) | `Bearer eyJhbGciOi...` | |
||||||
|
| `X-API-Key` | Custom API key for client authentication | `758b7d596dbc...` | |
||||||
|
| `X-Auth-Token` | Token-based session authentication | `d3f1c3a1-...` | |
||||||
|
| `X-Requested-With` | Identifies AJAX requests (legacy jQuery, CSRF checks) | `XMLHttpRequest` | |
||||||
|
| `Content-Type` | Declares request body format | `application/json` | |
||||||
|
| `Accept` | Declares expected response format | `application/json` | |
||||||
|
| `User-Agent` | Identifies client application | `MyApp/1.2.3` | |
||||||
|
| `X-Correlation-ID` | Tracks a request across distributed systems | `abc123-request-id` | |
||||||
|
| `X-Forwarded-For` | Shows originating IP behind proxies | `203.0.113.42` | |
||||||
|
| `X-Real-IP` | Alternate client IP header used by some proxies | `198.51.100.7` | |
||||||
|
| `If-None-Match` | Used with ETag for caching | `"abc123etag"` | |
||||||
|
| `If-Modified-Since` | Used for conditional GET requests | `Wed, 21 Oct 2015 07:28:00 GMT` | |
||||||
|
| `Cookie` | Sends session tokens or other state data | `session_id=abc123; logged_in=true` | |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## Response Headers |
||||||
|
|
||||||
|
| Header Name | Purpose | Example Value | |
||||||
|
|----------------------|-------------------------------------------------------|------------------------------------------------| |
||||||
|
| `Content-Type` | Format of the response body | `application/json` | |
||||||
|
| `Cache-Control` | Caching policy for the response | `no-cache`, `max-age=3600` | |
||||||
|
| `ETag` | Unique identifier for the response version | `"abc123etag"` | |
||||||
|
| `Last-Modified` | Timestamp of last modification | `Wed, 21 Oct 2015 07:28:00 GMT` | |
||||||
|
| `Expires` | Date/time when the response becomes stale | `Thu, 01 Dec 1994 16:00:00 GMT` | |
||||||
|
| `Location` | URL to newly created resource or redirect | `/users/123` or `https://api.example.com/...` | |
||||||
|
| `Retry-After` | Suggests wait time before retrying | `120` (seconds) or HTTP-date | |
||||||
|
| `WWW-Authenticate` | Declares required authentication scheme | `Bearer realm="example"` | |
||||||
|
| `Set-Cookie` | Sends cookies back to the client | `session_id=abc123; HttpOnly; Secure` | |
||||||
|
| `X-RateLimit-Limit` | Max requests allowed in current window | `1000` | |
||||||
|
| `X-RateLimit-Remaining` | Requests left in current window | `428` | |
||||||
|
| `X-RateLimit-Reset` | When rate limit resets (UNIX timestamp) | `1714684800` | |
||||||
|
| `X-Correlation-ID` | Unique ID for tracking this response (log tracing) | `abc123-response-id` | |
||||||
|
| `Access-Control-Allow-Origin` | CORS policy for allowed domains | `*` or `https://yourdomain.com` | |
||||||
|
| `Allow` | Accompanied with a 405 Response code | `GET,POST,PUT,DELETE` | |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## Nonce-Related Headers |
||||||
|
|
||||||
|
| Header Name | Purpose | Example Value | |
||||||
|
|---------------------------|-----------------------------------------------------|----------------------------------------------| |
||||||
|
| `Content-Security-Policy` | Allows inline scripts/styles with specific nonces | `script-src 'nonce-abc123'` | |
||||||
|
| `X-CSRF-Token` | Sends a per-request anti-CSRF token (often custom) | `e1f9e2d4-8f4b-4d2a-8450-c38a1fba57d4` | |
||||||
|
| `X-Nonce` (custom) | General-use nonce for replay prevention | `abc123noncevalue` | |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## Sample: Bearer Token in Authorization Header (PHP) |
||||||
|
|
||||||
|
```php |
||||||
|
$token = 'your-jwt-or-api-token'; |
||||||
|
$headers = [ |
||||||
|
'Authorization: Bearer ' . $token, |
||||||
|
# Alternately using API tokens |
||||||
|
# 'X-API-Key: ' . $apiKey, |
||||||
|
'Content-Type: application/json' |
||||||
|
]; |
||||||
|
|
||||||
|
$ch = curl_init('https://api.example.com/endpoint'); |
||||||
|
curl_setopt_array($ch, [ |
||||||
|
CURLOPT_RETURNTRANSFER => true, |
||||||
|
CURLOPT_HTTPHEADER => $headers |
||||||
|
]); |
||||||
|
|
||||||
|
$response = curl_exec($ch); |
||||||
|
curl_close($ch); |
||||||
|
``` |
||||||
|
|
||||||
|
## Sample: Bearer Token in Authorization Header (JavaScript / Fetch) |
||||||
|
|
||||||
|
```js |
||||||
|
const token = 'your-jwt-or-api-token'; |
||||||
|
|
||||||
|
fetch('https://api.example.com/endpoint', { |
||||||
|
method: 'GET', |
||||||
|
headers: { |
||||||
|
'Authorization': `Bearer ${token}`, |
||||||
|
'Content-Type': 'application/json', |
||||||
|
'Accept': 'application/json' |
||||||
|
} |
||||||
|
}) |
||||||
|
.then(response => response.json()) |
||||||
|
.then(data => console.log(data)) |
||||||
|
.catch(err => console.error('Request failed', err)); |
||||||
|
``` |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
## Sample: Content-Security-Policy Nonce (PHP) |
||||||
|
|
||||||
|
### Server-side nonce generation: |
||||||
|
|
||||||
|
```php |
||||||
|
$nonce = base64_encode(random_bytes(16)); |
||||||
|
header("Content-Security-Policy: script-src 'self' 'nonce-$nonce'"); |
||||||
|
``` |
||||||
|
|
||||||
|
### Outputting safe inline script: |
||||||
|
|
||||||
|
```php |
||||||
|
echo "<script nonce="$nonce">console.log('Safe inline script');</script>"; |
||||||
|
``` |
||||||
@ -0,0 +1,39 @@ |
|||||||
|
|
||||||
|
| Method | REST Purpose | Idempotent | Safe | Example | Typical Response Codes | |
||||||
|
|---------|----------------------------|------------|-------|------------------------------|--------------------------------------------------------| |
||||||
|
| GET | Retrieve a collection | ✔ Yes | ✔ Yes | `GET /users` | 200 OK, 204 No Content, 304 Not Modified | |
||||||
|
| GET | Retrieve a single resource | ✔ Yes | ✔ Yes | `GET /users/123` | 200 OK, 404 Not Found, 304 Not Modified | |
||||||
|
| POST | Create a new resource | ✖ No | ✖ No | `POST /users` | 201 Created, 400 Bad Request, 409 Conflict | |
||||||
|
| PUT | Replace a resource | ✔ Yes | ✖ No | `PUT /users/123` | 200 OK, 204 No Content, 400 Bad Request, 404 Not Found | |
||||||
|
| PATCH | Update part of a resource | ✖ No | ✖ No | `PATCH /users/123` | 200 OK, 204 No Content, 400 Bad Request, 404 Not Found | |
||||||
|
| DELETE | Remove a resource | ✔ Yes | ✖ No | `DELETE /users/123` | 204 No Content, 404 Not Found | |
||||||
|
| HEAD | Retrieve headers only | ✔ Yes | ✔ Yes | `HEAD /users/123` | 200 OK, 404 Not Found | |
||||||
|
| OPTIONS | Discover allowed methods | ✔ Yes | ✔ Yes | `OPTIONS /users` | 204 No Content, 405 Method Not Allowed | |
||||||
|
|
||||||
|
Typical Status codes to watch for: |
||||||
|
- 401 Unauthorized |
||||||
|
- 403 Forbidden |
||||||
|
- 500 Server Error |
||||||
|
|
||||||
|
| Status Code | Text Description | Typical REST Usage | |
||||||
|
|-------------|-------------------------|--------------------------------------------------------| |
||||||
|
| 200 | OK | Successful GET, PUT, or DELETE request | |
||||||
|
| 201 | Created | Resource successfully created (e.g., POST) | |
||||||
|
| 202 | Accepted | Request accepted for processing (async operations) | |
||||||
|
| 204 | No Content | Successful request with no response body (e.g., DELETE)| |
||||||
|
| 301 | Moved Permanently | Resource has moved (rare in REST APIs) | |
||||||
|
| 302 | Found | Temporary redirect (often avoided in APIs) | |
||||||
|
| 304 | Not Modified | Used with caching headers like ETag | |
||||||
|
| 400 | Bad Request | Malformed request, missing parameters, etc. | |
||||||
|
| 401 | Unauthorized | Authentication required or failed | |
||||||
|
| 403 | Forbidden | Authenticated but not authorized | |
||||||
|
| 404 | Not Found | Resource not found | |
||||||
|
| 405 | Method Not Allowed | HTTP method not supported for this endpoint | |
||||||
|
| 409 | Conflict | Request conflicts with current state (e.g., duplicate) | |
||||||
|
| 410 | Gone | Resource no longer available | |
||||||
|
| 415 | Unsupported Media Type | Content-Type not supported (e.g., expecting JSON) | |
||||||
|
| 422 | Unprocessable Entity | Validation error (common in POST/PUT with payloads) | |
||||||
|
| 429 | Too Many Requests | Rate limiting exceeded | |
||||||
|
| 500 | Internal Server Error | Generic server error | |
||||||
|
| 501 | Not Implemented | Endpoint or method not supported | |
||||||
|
| 503 | Service Unavailable | Server is down or overloaded | |
||||||
@ -0,0 +1,55 @@ |
|||||||
|
<?php |
||||||
|
class Redirect { |
||||||
|
__construct($endpoint, $apiKey) { |
||||||
|
$this->endpoint = $endpoint; |
||||||
|
$this->apiKey = $apiKey; |
||||||
|
} |
||||||
|
function _call() { |
||||||
|
$ch = curl_init($endpoint); |
||||||
|
|
||||||
|
curl_setopt_array($ch, [ |
||||||
|
CURLOPT_RETURNTRANSFER => true, |
||||||
|
CURLOPT_HTTPHEADER => [ |
||||||
|
'Accept: application/json', |
||||||
|
'Content-Type: application/json', |
||||||
|
"X-API-Key: $apikey", |
||||||
|
], |
||||||
|
]); |
||||||
|
|
||||||
|
$response = curl_exec($ch); |
||||||
|
|
||||||
|
if (curl_errno($ch)) { |
||||||
|
curl_close($ch); |
||||||
|
throw new Exception(curl_error($ch)); |
||||||
|
} else { |
||||||
|
curl_close($ch); |
||||||
|
print_r($httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); |
||||||
|
return (object)[ 'status' => httpCode, 'response' => json_decode($response)]; |
||||||
|
} |
||||||
|
function add($payload) { |
||||||
|
$ch = curl_init($endpoint); |
||||||
|
|
||||||
|
curl_setopt_array($ch, [ |
||||||
|
CURLOPT_RETURNTRANSFER => true, |
||||||
|
CURLOPT_POST => true, |
||||||
|
CURLOPT_HTTPHEADER => [ |
||||||
|
'Accept: application/json', |
||||||
|
'Content-Type: application/json', |
||||||
|
"X-API-Key: $apikey", |
||||||
|
], |
||||||
|
CURLOPT_POSTFIELDS => json_encode($payload), |
||||||
|
]); |
||||||
|
|
||||||
|
$response = curl_exec($ch); |
||||||
|
|
||||||
|
if (curl_errno($ch)) { |
||||||
|
curl_close($ch); |
||||||
|
throw new Exception(curl_error($ch)); |
||||||
|
} else { |
||||||
|
curl_close($ch); |
||||||
|
print_r($httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); |
||||||
|
return (object)[ 'status' => httpCode, 'response' => json_decode($response)]; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,74 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
/* |
||||||
|
* New PHP REST Framework |
||||||
|
* |
||||||
|
* Using Following SPECS |
||||||
|
* - HTTP Status Codes https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status |
||||||
|
* - HTTP Methods https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Methods |
||||||
|
* - REST API https://restfulapi.net/http-methods/ |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* Determines whether the incoming request has a JSON-based Content-Type. |
||||||
|
* |
||||||
|
* @param string|null $contentType Optional override for testing or CLI use. |
||||||
|
* @return bool True if the Content-Type indicates JSON. |
||||||
|
*/ |
||||||
|
function req_isjson(?string $contentType = null): bool { |
||||||
|
// Get the header from the server if not provided |
||||||
|
$type = $contentType ?? ($_SERVER['CONTENT_TYPE'] ?? ''); |
||||||
|
|
||||||
|
// Normalize and strip parameters like "; charset=utf-8" |
||||||
|
$type = strtolower(trim(explode(';', $type)[0])); |
||||||
|
|
||||||
|
// Known JSON-based media types |
||||||
|
$jsonTypes = [ |
||||||
|
'application/json', |
||||||
|
'application/ld+json', |
||||||
|
'application/vnd.api+json', // JSON:API spec |
||||||
|
'text/json', // Rare but occasionally seen |
||||||
|
]; |
||||||
|
|
||||||
|
return in_array($type, $jsonTypes, true); |
||||||
|
} |
||||||
|
|
||||||
|
function req_method($supported = ['GET','PUT','POST','DELETE','HEAD','OPTIONS'],?string $method = null): string { |
||||||
|
// Get the header from the server if not provided |
||||||
|
$method = $method ?? ($_SERVER['REQUEST_METHOD'] ?? ''); |
||||||
|
if (!in_array($_SERVER['REQUEST_METHOD'], $supported)) { |
||||||
|
http_response_code(405); |
||||||
|
header('Allow: '. join(',',$supported)); |
||||||
|
exit; |
||||||
|
} |
||||||
|
return $method; |
||||||
|
} |
||||||
|
|
||||||
|
if (req_isjson()) { |
||||||
|
$raw = file_get_contents('php://input'); |
||||||
|
|
||||||
|
$post =json_decode($raw,true,1000,JSON_INVALID_UTF8_IGNORE); |
||||||
|
|
||||||
|
if (json_last_error() !== JSON_ERROR_NONE) { |
||||||
|
throw new JSONException('JSON: '.json_last_error_msg()); |
||||||
|
} |
||||||
|
} else { |
||||||
|
$post = $_REQUEST; |
||||||
|
} |
||||||
|
var_dump($_POST); |
||||||
|
$req = (object)[ |
||||||
|
'isjson' => req_isjson(), |
||||||
|
'method' => req_method(['GET','POST']), |
||||||
|
'path' => $_SERVER['PATH_INFO'] ?? '/', |
||||||
|
'post' => $post, |
||||||
|
]; |
||||||
|
|
||||||
|
$res = (object)[ |
||||||
|
'result' => 'ok', |
||||||
|
'req' => $req, |
||||||
|
]; |
||||||
|
|
||||||
|
|
||||||
|
header('Content-Type: application/json'); |
||||||
|
echo json_encode([$res], JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT); |
||||||
|
|
||||||
Loading…
Reference in new issue