A comprehensive RESTful API for managing orders and payments with JWT authentication, built with Laravel 10.x following clean code principles and design patterns.
- JWT Authentication: Secure API endpoints with JWT tokens
- Order Management: Full CRUD operations for orders and order items
- Payment Processing: Multiple payment gateway support with Strategy pattern
- Extensible Architecture: Easy to add new payment gateways
- Database Transactions: Atomic operations for order creation
- Soft Deletes: Safe deletion with recovery capability
- API Resources: Standardized response transformation
- Comprehensive Testing: Unit and feature tests
- Validation: Form request validation with custom error messages
- Laravel: 10.x
- PHP: 8.1+
- MySQL: Database
- JWT: tymon/jwt-auth for authentication
- PHPUnit: Testing framework
- PSR-12: Coding standards
app/
├── Contracts/ # Interfaces and abstract classes
│ ├── PaymentGatewayInterface.php
│ └── PaymentResult.php
├── Exceptions/ # Custom exception classes
│ ├── OrderException.php
│ └── PaymentProcessingException.php
├── Http/
│ ├── Controllers/Api/ # API controllers
│ │ ├── AuthController.php
│ │ ├── OrderController.php
│ │ └── PaymentController.php
│ ├── Requests/ # Form request validation
│ │ ├── RegisterRequest.php
│ │ ├── LoginRequest.php
│ │ ├── CreateOrderRequest.php
│ │ ├── UpdateOrderRequest.php
│ │ └── ProcessPaymentRequest.php
│ └── Resources/ # API resource classes
│ ├── UserResource.php
│ ├── OrderResource.php
│ ├── OrderItemResource.php
│ └── PaymentResource.php
├── Models/ # Eloquent models
│ ├── User.php
│ ├── Order.php
│ ├── OrderItem.php
│ ├── Payment.php
│ └── PaymentGateway.php
└── Services/
├── OrderService.php # Order business logic
├── PaymentService.php # Payment orchestration
└── PaymentGateways/ # Concrete gateway implementations
├── CreditCardGateway.php
├── PayPalGateway.php
└── StripeGateway.php
database/
├── migrations/ # Database migrations
└── seeders/ # Database seeders
tests/
├── Feature/ # Feature tests
│ ├── AuthenticationTest.php
│ ├── OrderTest.php
│ └── PaymentTest.php
└── Unit/ # Unit tests
├── PaymentGatewayTest.php
└── OrderServiceTest.php
- PHP 8.1 or higher
- Composer
- MySQL 5.7 or higher
- Git
-
Clone the repository
git clone <repository-url> cd API-Gateway
-
Install dependencies
composer install
-
Configure environment
cp .env.example .env
-
Generate application key
php artisan key:generate
-
Generate JWT secret
php artisan jwt:secret
-
Configure database (edit
.env)DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=api_gateway DB_USERNAME=root DB_PASSWORD=
-
Run migrations
php artisan migrate
-
Seed the database (optional)
php artisan db:seed
-
Start the development server
php artisan serve
The API will be available at
http://localhost:8000
http://localhost:8000/api
All responses follow a standardized format:
Success Response:
{
"success": true,
"message": "Operation successful",
"data": {...}
}Error Response:
{
"success": false,
"message": "Error description",
"error": "detailed error information"
}Paginated Response:
{
"data": [...],
"links": {...},
"meta": {
"current_page": 1,
"per_page": 15,
"total": 100
}
}POST /api/register
Content-Type: application/json
{
"name": "John Doe",
"email": "[email protected]",
"password": "password123",
"password_confirmation": "password123"
}Response: 201 Created
{
"success": true,
"message": "User registered successfully",
"data": {
"user": {
"id": 1,
"name": "John Doe",
"email": "[email protected]",
"created_at": "2024-01-26T10:00:00Z"
},
"token": "eyJ0eXAiOiJKV1QiLCJhbGc..."
}
}POST /api/login
Content-Type: application/json
{
"email": "[email protected]",
"password": "password123"
}Response: 200 OK
{
"success": true,
"message": "Login successful",
"data": {
"user": {
"id": 1,
"name": "John Doe",
"email": "[email protected]"
},
"token": "eyJ0eXAiOiJKV1QiLCJhbGc..."
}
}GET /api/me
Authorization: Bearer {token}Response: 200 OK
{
"success": true,
"message": "User retrieved successfully",
"data": {
"id": 1,
"name": "John Doe",
"email": "[email protected]",
"created_at": "2024-01-26T10:00:00Z"
}
}POST /api/logout
Authorization: Bearer {token}Response: 200 OK
{
"success": true,
"message": "Logout successful"
}POST /api/orders
Authorization: Bearer {token}
Content-Type: application/json
{
"items": [
{
"product_name": "Laptop",
"quantity": 1,
"price": 999.99
},
{
"product_name": "Mouse",
"quantity": 2,
"price": 29.99
}
]
}Response: 201 Created
{
"success": true,
"message": "Order created successfully",
"data": {
"id": 1,
"user_id": 1,
"total_amount": 1059.97,
"status": "pending",
"items": [
{
"id": 1,
"product_name": "Laptop",
"quantity": 1,
"price": 999.99,
"total": 999.99
},
{
"id": 2,
"product_name": "Mouse",
"quantity": 2,
"price": 29.99,
"total": 59.98
}
],
"payments": []
}
}GET /api/orders?status=pending&per_page=15
Authorization: Bearer {token}Query Parameters:
status: Filter by order status (pending, confirmed, cancelled)per_page: Number of results per page (default: 15)page: Page number (default: 1)
Response: 200 OK
{
"data": [
{
"id": 1,
"user_id": 1,
"total_amount": 1059.97,
"status": "pending",
"created_at": "2024-01-26T10:00:00Z"
}
],
"links": {
"first": "http://localhost:8000/api/orders?page=1",
"last": "http://localhost:8000/api/orders?page=1",
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 1,
"per_page": 15,
"to": 1,
"total": 1
}
}GET /api/orders/{id}
Authorization: Bearer {token}Response: 200 OK
PUT /api/orders/{id}
Authorization: Bearer {token}
Content-Type: application/json
{
"status": "confirmed"
}Valid Statuses: pending, confirmed, cancelled
Response: 200 OK
DELETE /api/orders/{id}
Authorization: Bearer {token}Response: 200 OK
{
"success": true,
"message": "Order deleted successfully"
}POST /api/orders/{id}/payments
Authorization: Bearer {token}
Content-Type: application/json
{
"payment_method": "credit_card",
"card_number": "4111111111111111",
"card_holder": "John Doe",
"expiry_month": 12,
"expiry_year": 2025,
"cvv": "123"
}POST /api/orders/{id}/payments
Authorization: Bearer {token}
Content-Type: application/json
{
"payment_method": "paypal",
"paypal_email": "[email protected]"
}POST /api/orders/{id}/payments
Authorization: Bearer {token}
Content-Type: application/json
{
"payment_method": "stripe",
"stripe_token": "tok_visa"
}Response: 201 Created
{
"success": true,
"message": "Payment processed successfully",
"data": {
"id": 1,
"order_id": 1,
"payment_gateway": "credit_card",
"amount": 1059.97,
"status": "successful",
"transaction_id": "CC_1_abc123def",
"payment_data": {
"card_last_four": "1111",
"amount": 1059.97,
"request_timestamp": "2024-01-26T10:05:00Z"
}
}
}GET /api/orders/{id}/payments?per_page=15
Authorization: Bearer {token}Response: 200 OK (Paginated collection)
GET /api/payments?status=successful&gateway=stripe&per_page=15
Authorization: Bearer {token}Query Parameters:
status: Filter by status (pending, successful, failed)gateway: Filter by gateway (credit_card, paypal, stripe)per_page: Results per page (default: 15)
Response: 200 OK (Paginated collection)
GET /api/payments/{id}
Authorization: Bearer {token}Response: 200 OK
The API uses the Strategy Pattern for payment gateways, making it easy to add new ones.
Create a new file in app/Services/PaymentGateways/YourGateway.php:
<?php
namespace App\Services\PaymentGateways;
use App\Contracts\PaymentGatewayInterface;
use App\Contracts\PaymentResult;
use App\Models\Order;
use App\Models\Payment;
class YourGateway implements PaymentGatewayInterface
{
/**
* Process a payment using your gateway.
*/
public function processPayment(Order $order, array $paymentData): PaymentResult
{
// Validate payment data
if (!$this->validateData($paymentData)) {
return PaymentResult::failure('Invalid payment data');
}
// Process payment through your gateway
$transactionId = 'YOUR_' . $order->id . '_' . uniqid();
$success = true; // Simulate or make actual API call
if ($success) {
return PaymentResult::success(
$transactionId,
'Payment successful',
['gateway_response' => 'data']
);
}
return PaymentResult::failure('Payment failed');
}
/**
* Refund a payment.
*/
public function refund(Payment $payment): bool
{
// Implement refund logic
return true;
}
/**
* Get the gateway name.
*/
public function getGatewayName(): string
{
return 'your_gateway';
}
/**
* Validate payment data.
*/
private function validateData(array $data): bool
{
// Add your validation logic
return true;
}
}Register your gateway in app/Services/PaymentService.php:
private array $gateways = [
'credit_card' => CreditCardGateway::class,
'paypal' => PayPalGateway::class,
'stripe' => StripeGateway::class,
'your_gateway' => YourGateway::class, // Add this line
];Or dynamically register it:
$paymentService->registerGateway('your_gateway', YourGateway::class);Update app/Http/Requests/ProcessPaymentRequest.php to include validation for your gateway:
case 'your_gateway':
$rules['your_gateway_field'] = ['required', 'string'];
break;Create tests for your gateway in tests/Unit/PaymentGatewayTest.php:
public function test_your_gateway_processes_payment(): void
{
$gateway = new YourGateway();
$result = $gateway->processPayment($this->order, [
'your_gateway_field' => 'value',
]);
$this->assertInstanceOf(PaymentResult::class, $result);
$this->assertTrue($result->success || !$result->success);
}- Payments can only be processed for confirmed orders - Orders must have status 'confirmed' before payment processing
- Orders cannot be deleted if they have payments - Safety mechanism to prevent data loss
- Order total is calculated automatically - Total is computed from items (quantity × price)
- All inputs are validated - Server-side validation on all API endpoints
- Meaningful error messages - Clear, actionable error responses
- Proper HTTP status codes - Industry-standard status codes used throughout
php artisan testphp artisan test tests/Feature/AuthenticationTest.phpphp artisan test --coveragephp artisan test tests/Unitphp artisan test tests/FeatureThe API provides comprehensive error handling with meaningful messages:
{
"success": false,
"message": "Validation failed",
"errors": {
"email": ["Email is already registered"],
"password": ["Password must be at least 8 characters"]
}
}{
"success": false,
"message": "Invalid credentials"
}{
"success": false,
"message": "Unauthorized"
}{
"success": false,
"message": "Resource not found"
}{
"success": false,
"message": "An error occurred",
"error": "Error details"
}id- Primary keyname- User nameemail- Unique emailpassword- Hashed passwordtimestamps- created_at, updated_at
id- Primary keyuser_id- Foreign key to userstotal_amount- Decimal(10,2)status- Enum: pending, confirmed, cancelleddeleted_at- Soft deletetimestamps- created_at, updated_at
id- Primary keyorder_id- Foreign key to ordersproduct_name- Stringquantity- Integerprice- Decimal(10,2)deleted_at- Soft deletetimestamps- created_at, updated_at
id- Primary keyorder_id- Foreign key to orderspayment_gateway- Stringamount- Decimal(10,2)status- Enum: pending, successful, failedtransaction_id- Unique identifierpayment_data- JSONdeleted_at- Soft deletetimestamps- created_at, updated_at
id- Primary keyname- Unique nameis_active- Booleanconfig- JSONdeleted_at- Soft deletetimestamps- created_at, updated_at
- Eager loading: Related data is loaded efficiently using
load()andwith() - Pagination: Large datasets are paginated (default 15 per page)
- Database transactions: Multi-step operations use transactions for consistency
- Indexes: Foreign keys and unique fields are indexed
- JWT Authentication: Secure token-based authentication
- Password Hashing: Passwords hashed with bcrypt
- Authorization: All protected routes check user ownership
- Input Validation: All inputs validated before processing
- SQL Injection Prevention: Using Eloquent ORM
- CORS: Can be configured as needed
Key environment variables in .env:
APP_NAME="Order Payment API"
APP_ENV=local
APP_DEBUG=true
APP_URL=http://localhost
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_DATABASE=api_gateway
DB_USERNAME=root
DB_PASSWORD=
JWT_SECRET=your-secret-key-here
JWT_ALGORITHM=HS256
STRIPE_API_KEY=sk_test_your_key
PAYPAL_CLIENT_ID=your_client_id
PAYPAL_CLIENT_SECRET=your_secret- Refresh your token using
/api/refreshendpoint
- Ensure token is included in Authorization header as
Bearer {token}
- Update order status to 'confirmed' using PUT
/api/orders/{id}
- Only orders without payments can be deleted
- Verify MySQL is running
- Check database credentials in
.env - Ensure database exists:
CREATE DATABASE api_gateway;
- Create a feature branch:
git checkout -b feature/your-feature - Make changes and commit:
git commit -am 'Add new feature' - Write tests for new features
- Run tests to ensure everything passes:
php artisan test - Push to repository:
git push origin feature/your-feature - Create a pull request
- Follow PSR-12 coding standards
- Write tests for all new features
- Ensure all tests pass
- Update documentation as needed
This project is open source and available under the MIT license.
For issues, questions, or suggestions, please open an issue in the repository.
Last Updated: January 26, 2024