Maak een PHP-API voor gegevensuitwisseling
description
Met deze prompt kan de gebruiker een robuuste PHP-API ontwikkelen die data veilig en efficiënt uitwisselt, waardoor integratie met externe diensten eenvoudig wordt. Het bespaart tijd en biedt duidelijke richtlijnen voor best practices in API-ontwikkeling.
prompt
Help me bij het ontwerpen en implementeren van een PHP-API die data uitwisselt tussen mijn applicatie en externe systemen. Beschrijf hierbij hoe ik RE ...
try_prompt
generate_helper
disclaimerOnPageApi
tags
ai_answers
provider: openai
model: gpt-4.1-nano
Natuurlijk! Hier is een overzicht van hoe je een PHP-API kunt ontwerpen en implementeren die data uitwisselt tussen jouw applicatie en externe systemen, inclusief RESTful endpoints, authenticatie en gegevensvalidatie voor productbeheer en voorraadbeheer.
1. Structuur van de API
- Bestanden en mappen
- `index.php` of een routerbestand voor het afhandelen van verzoeken
- `api/` map met aparte bestanden voor elk resource zoals `producten.php`
- `config/` voor configuratie en databaseverbinding
- `models/` voor database-interacties
- `auth/` voor authenticatie-logica
- Database
- Tabel `producten` met velden zoals `id`, `naam`, `beschrijving`, `prijs`, `voorraad`, `created_at`, `updated_at`
2. RESTful Endpoints
Gebruik HTTP-methoden voor CRUD-operaties:
- `GET /producten` — lijst alle producten
- `GET /producten/{id}` — haal een specifiek product op
- `POST /producten` — voeg een nieuw product toe
- `PUT /producten/{id}` — werk een bestaand product bij
- `DELETE /producten/{id}` — verwijder een product
3. Routing en verwerking
- Gebruik bijvoorbeeld `.htaccess` of een routingbibliotheek om URLs te herschrijven
- In `index.php` detecteer je de HTTP-verbinding en route je naar de juiste functie
4. Authenticatie
- Implementatie van API-sleutels of Bearer tokens (bijv. JWT)
- Voorbeeld: API-sleutel in headers (`Authorization: Bearer <token>`)
- Validatie: controleer of de token geldig is voordat je gegevens verwerkt
5. Gegevensvalidatie
- Controleer of alle verplichte velden aanwezig en correct zijn
- Bijvoorbeeld: naam niet leeg, prijs numeriek en positief, voorraad integer
- Gebruik PHP-functies of libraries zoals `filter_var()` en aangepaste validaties
6. Voorbeeldimplementatie (vereenvoudigd)
```php
// index.php
header('Content-Type: application/json');
// Verbind met database
require 'config/database.php';
// Authenticatie
$headers = apache_request_headers();
if (!isset($headers['Authorization'])) {
http_response_code(401);
echo json_encode(['error' => 'Geen authenticatieheader gevonden']);
exit;
}
$authHeader = $headers['Authorization'];
// Veronderstel Bearer token
if (!preg_match('/Bearer\s(\S+)/', $authHeader, $matches)) {
http_response_code(401);
echo json_encode(['error' => 'Ongeldige authenticatie header']);
exit;
}
$token = $matches[1];
// Controleer token (voorbeeld)
if ($token !== 'jouw_secret_token') {
http_response_code(403);
echo json_encode(['error' => 'Ongeldige token']);
exit;
}
// Routing
$method = $_SERVER['REQUEST_METHOD'];
$path = trim($_SERVER['PATH_INFO'], '/');
$parts = explode('/', $path);
if ($parts[0] === 'producten') {
require 'api/producten.php';
} else {
http_response_code(404);
echo json_encode(['error' => 'Niet gevonden']);
}
```
```php
// api/producten.php
switch ($method) {
case 'GET':
if (isset($parts[1])) {
// Haal product op
getProduct($pdo, $parts[1]);
} else {
// Haal alle producten op
getAlleProducten($pdo);
}
break;
case 'POST':
addProduct($pdo);
break;
case 'PUT':
if (isset($parts[1])) {
updateProduct($pdo, $parts[1]);
}
break;
case 'DELETE':
if (isset($parts[1])) {
deleteProduct($pdo, $parts[1]);
}
break;
default:
http_response_code(405);
echo json_encode(['error' => 'Method niet toegestaan']);
}
function getAlleProducten($pdo) {
// Query database
$stmt = $pdo->query('SELECT * FROM producten');
$producten = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo json_encode($producten);
}
function getProduct($pdo, $id) {
$stmt = $pdo->prepare('SELECT * FROM producten WHERE id = :id');
$stmt->execute([':id' => $id]);
$product = $stmt->fetch(PDO::FETCH_ASSOC);
if ($product) {
echo json_encode($product);
} else {
http_response_code(404);
echo json_encode(['error' => 'Product niet gevonden']);
}
}
function addProduct($pdo) {
$data = json_decode(file_get_contents('php://input'), true);
// Validatie
if (empty($data['naam']) || !is_numeric($data['prijs']) || !is_int($data['voorraad'])) {
http_response_code(400);
echo json_encode(['error' => 'Ongeldige gegevens']);
return;
}
$stmt = $pdo->prepare('INSERT INTO producten (naam, beschrijving, prijs, voorraad) VALUES (:naam, :beschrijving, :prijs, :voorraad)');
$stmt->execute([
':naam' => $data['naam'],
':beschrijving' => $data['beschrijving'] ?? '',
':prijs' => $data['prijs'],
':voorraad' => $data['voorraad']
]);
echo json_encode(['message' => 'Product toegevoegd', 'id' => $pdo->lastInsertId()]);
}
function updateProduct($pdo, $id) {
$data = json_decode(file_get_contents('php://input'), true);
// Validatie
if (isset($data['naam']) && empty($data['naam'])) {
http_response_code(400);
echo json_encode(['error' => 'Naam mag niet leeg zijn']);
return;
}
// Update query
$sql = 'UPDATE producten SET ';
$updates = [];
$params = [];
if (isset($data['naam'])) {
$updates[] = 'naam = :naam';
$params[':naam'] = $data['naam'];
}
if (isset($data['beschrijving'])) {
$updates[] = 'beschrijving = :beschrijving';
$params[':beschrijving'] = $data['beschrijving'];
}
if (isset($data['prijs'])) {
if (!is_numeric($data['prijs'])) {
http_response_code(400);
echo json_encode(['error' => 'Ongeldig prijs']);
return;
}
$updates[] = 'prijs = :prijs';
$params[':prijs'] = $data['prijs'];
}
if (isset($data['voorraad'])) {
if (!is_int($data['voorraad'])) {
http_response_code(400);
echo json_encode(['error' => 'Ongeldige voorraad']);
return;
}
$updates[] = 'voorraad = :voorraad';
$params[':voorraad'] = $data['voorraad'];
}
if (empty($updates)) {
http_response_code(400);
echo json_encode(['error' => 'Geen gegevens om bij te werken']);
return;
}
$sql .= implode(', ', $updates) . ' WHERE id = :id';
$params[':id'] = $id;
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
echo json_encode(['message' => 'Product bijgewerkt']);
}
function deleteProduct($pdo, $id) {
$stmt = $pdo->prepare('DELETE FROM producten WHERE id = :id');
$stmt->execute([':id' => $id]);
echo json_encode(['message' => 'Product verwijderd']);
}
```
7. Voorraadbeheer
- Bij het bijwerken van een product kun je de voorraad aanpassen
- Mogelijkheid om voorraad te verhogen/verlagen via aparte endpoints of in de updatefunctie
8. Samenvatting
- Gebruik RESTful principes voor duidelijke URLs en methoden
- Implementeer token-gebaseerde authenticatie voor beveiliging
- Valideer alle invoer streng om data-integriteit te waarborgen
- Gebruik PDO voor veilige database-interacties (prepared statements)
Met deze aanpak heb je een solide basis voor jouw PHP-API voor product- en voorraadbeheer.
provider: deepseek
model: deepseek-chat
Zeker, ik help je bij het ontwerpen en implementeren van een RESTful PHP-API voor productbeheer. Hier is een complete handleiding:
## 1. Projectstructuur
```
/api/
├── config/
│ ├── database.php
│ └── cors.php
├── controllers/
│ └── ProductController.php
├── models/
│ └── Product.php
├── middleware/
│ ├── AuthMiddleware.php
│ └── ValidationMiddleware.php
├── routes/
│ └── api.php
└── index.php
```
## 2. RESTful Endpoints Ontwerp
```php
// routes/api.php
<?php
use App\Controllers\ProductController;
use App\Middleware\AuthMiddleware;
use App\Middleware\ValidationMiddleware;
// Product endpoints
$app->get('/products', [ProductController::class, 'index']);
$app->get('/products/{id}', [ProductController::class, 'show']);
$app->post('/products', [ProductController::class, 'store'])->add(new AuthMiddleware())->add(new ValidationMiddleware());
$app->put('/products/{id}', [ProductController::class, 'update'])->add(new AuthMiddleware())->add(new ValidationMiddleware());
$app->delete('/products/{id}', [ProductController::class, 'destroy'])->add(new AuthMiddleware());
```
## 3. Authenticatie Implementatie (JWT)
```php
// middleware/AuthMiddleware.php
<?php
namespace App\Middleware;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface as Handler;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
class AuthMiddleware
{
public function __invoke(Request $request, Handler $handler)
{
$token = $request->getHeaderLine('Authorization');
if (empty($token)) {
return new Response(401, ['Content-Type' => 'application/json'],
json_encode(['error' => 'Authenticatie vereist']));
}
try {
$token = str_replace('Bearer ', '', $token);
$decoded = JWT::decode($token, new Key($_ENV['JWT_SECRET'], 'HS256'));
$request = $request->withAttribute('user_id', $decoded->user_id);
return $handler->handle($request);
} catch (\Exception $e) {
return new Response(401, ['Content-Type' => 'application/json'],
json_encode(['error' => 'Ongeldig token']));
}
}
}
```
## 4. Gegevensvalidatie
```php
// middleware/ValidationMiddleware.php
<?php
namespace App\Middleware;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface as Handler;
class ValidationMiddleware
{
public function __invoke(Request $request, Handler $handler)
{
$data = $request->getParsedBody();
$errors = [];
// Validatieregels voor product
if (empty($data['naam'])) {
$errors[] = 'Naam is verplicht';
}
if (!isset($data['prijs']) || !is_numeric($data['prijs']) || $data['prijs'] <= 0) {
$errors[] = 'Prijs moet een positief getal zijn';
}
if (isset($data['voorraad']) && (!is_numeric($data['voorraad']) || $data['voorraad'] < 0)) {
$errors[] = 'Voorraad moet een niet-negatief getal zijn';
}
if (!empty($errors)) {
return new Response(400, ['Content-Type' => 'application/json'],
json_encode(['errors' => $errors]));
}
return $handler->handle($request);
}
}
```
## 5. Product Controller
```php
// controllers/ProductController.php
<?php
namespace App\Controllers;
use App\Models\Product;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
class ProductController
{
public function index(Request $request, Response $response): Response
{
$products = Product::getAll();
$response->getBody()->write(json_encode($products));
return $response->withHeader('Content-Type', 'application/json');
}
public function show(Request $request, Response $response, array $args): Response
{
$product = Product::find($args['id']);
if (!$product) {
$response->getBody()->write(json_encode(['error' => 'Product niet gevonden']));
return $response->withStatus(404)->withHeader('Content-Type', 'application/json');
}
$response->getBody()->write(json_encode($product));
return $response->withHeader('Content-Type', 'application/json');
}
public function store(Request $request, Response $response): Response
{
$data = $request->getParsedBody();
$productId = Product::create([
'naam' => $data['naam'],
'beschrijving' => $data['beschrijving'] ?? '',
'prijs' => $data['prijs'],
'voorraad' => $data['voorraad'] ?? 0,
'categorie' => $data['categorie'] ?? ''
]);
$response->getBody()->write(json_encode([
'message' => 'Product toegevoegd',
'product_id' => $productId
]));
return $response->withStatus(201)->withHeader('Content-Type', 'application/json');
}
public function update(Request $request, Response $response, array $args): Response
{
$data = $request->getParsedBody();
$updated = Product::update($args['id'], $data);
if (!$updated) {
$response->getBody()->write(json_encode(['error' => 'Product niet gevonden']));
return $response->withStatus(404)->withHeader('Content-Type', 'application/json');
}
$response->getBody()->write(json_encode(['message' => 'Product bijgewerkt']));
return $response->withHeader('Content-Type', 'application/json');
}
public function destroy(Request $request, Response $response, array $args): Response
{
$deleted = Product::delete($args['id']);
if (!$deleted) {
$response->getBody()->write(json_encode(['error' => 'Product niet gevonden']));
return $response->withStatus(404)->withHeader('Content-Type', 'application/json');
}
$response->getBody()->write(json_encode(['message' => 'Product verwijderd']));
return $response->withHeader('Content-Type', 'application/json');
}
}
```
## 6. Database Configuratie
```php
// config/database.php
<?php
class Database
{
private static $connection = null;
public static function getConnection()
{
if (self::$connection === null) {
try {
self::$connection = new PDO(
"mysql:host=" . $_ENV['DB_HOST'] . ";dbname=" . $_ENV['DB_NAME'],
$_ENV['DB_USER'],
$_ENV['DB_PASS']
);
self::$connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("Database connectie mislukt: " . $e->getMessage());
}
}
return self::$connection;
}
}
```
## 7. Gebruik van de API
**Producten ophalen:**
```bash
GET /api/products
```
**Product toevoegen:**
```bash
POST /api/products
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json
{
"naam": "iPhone 15",
"prijs": 999.99,
"voorraad": 50,
"categorie": "Electronica"
}
```
## 8. Beveiligingstips
1. **HTTPS**: Gebruik altijd HTTPS in productie
2. **Rate Limiting**: Implementeer rate limiting voor misbruikpreventie
3. **Input Sanitization**: Sanitiseer alle gebruikersinput
4. **CORS**: Configureer CORS headers juist
5. **Error Handling**: Geef geen gevoelige informatie in errors
## 9. Benodigde Packages
Installeer via Composer:
```bash
composer require slim/slim
composer require firebase/php-jwt
composer require vlucas/phpdotenv
```
Dit ontwerp biedt een schaalbare, veilige RESTful API voor productbeheer met volledige CRUD-functionaliteit en voorraadbeheer.
error: Generation failed [deepseek] prompt_id=1236 locale=en err=DeepSeek connection/timeout