xpeditis2.0/postman/Xpeditis_API.postman_collection.json
David-Henri ARNAUD 10bfffeef5 feature postman
2025-10-08 17:04:39 +02:00

580 lines
19 KiB
JSON

{
"info": {
"_postman_id": "xpeditis-api-collection",
"name": "Xpeditis API - Maritime Freight Booking",
"description": "Collection complète pour tester l'API Xpeditis - Plateforme de réservation de fret maritime B2B\n\n**Base URL:** http://localhost:4000\n\n**Fonctionnalités:**\n- Recherche de tarifs maritimes multi-transporteurs\n- Création et gestion de réservations\n- Validation automatique des données\n- Cache Redis (15 min)\n\n**Phase actuelle:** MVP Phase 1\n**Authentication:** À implémenter en Phase 2",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
{
"name": "Rates API",
"description": "Recherche de tarifs maritimes auprès de plusieurs transporteurs (Maersk, MSC, CMA CGM, etc.)",
"item": [
{
"name": "Search Rates - Rotterdam to Shanghai",
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test(\"Status code is 200\", function () {",
" pm.response.to.have.status(200);",
"});",
"",
"pm.test(\"Response has quotes array\", function () {",
" var jsonData = pm.response.json();",
" pm.expect(jsonData).to.have.property('quotes');",
" pm.expect(jsonData.quotes).to.be.an('array');",
"});",
"",
"pm.test(\"Response time is acceptable\", function () {",
" pm.expect(pm.response.responseTime).to.be.below(3000);",
"});",
"",
"// Save first quote ID for booking tests",
"if (pm.response.json().quotes.length > 0) {",
" pm.environment.set(\"rateQuoteId\", pm.response.json().quotes[0].id);",
" console.log(\"Saved rateQuoteId: \" + pm.response.json().quotes[0].id);",
"}"
],
"type": "text/javascript"
}
}
],
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"origin\": \"NLRTM\",\n \"destination\": \"CNSHA\",\n \"containerType\": \"40HC\",\n \"mode\": \"FCL\",\n \"departureDate\": \"2025-02-15\",\n \"quantity\": 2,\n \"weight\": 20000,\n \"isHazmat\": false\n}"
},
"url": {
"raw": "{{baseUrl}}/api/v1/rates/search",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"v1",
"rates",
"search"
]
},
"description": "Recherche de tarifs maritimes pour Rotterdam → Shanghai\n\n**Paramètres:**\n- `origin`: Code UN/LOCODE (5 caractères) - NLRTM = Rotterdam\n- `destination`: Code UN/LOCODE - CNSHA = Shanghai\n- `containerType`: 40HC (40ft High Cube)\n- `mode`: FCL (Full Container Load)\n- `departureDate`: Date de départ souhaitée\n- `quantity`: Nombre de conteneurs\n- `weight`: Poids total en kg\n\n**Cache:** Résultats mis en cache pendant 15 minutes"
},
"response": []
},
{
"name": "Search Rates - Hamburg to Los Angeles",
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test(\"Status code is 200\", function () {",
" pm.response.to.have.status(200);",
"});",
"",
"pm.test(\"Count matches quotes array length\", function () {",
" var jsonData = pm.response.json();",
" pm.expect(jsonData.count).to.equal(jsonData.quotes.length);",
"});"
],
"type": "text/javascript"
}
}
],
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"origin\": \"DEHAM\",\n \"destination\": \"USLAX\",\n \"containerType\": \"40DRY\",\n \"mode\": \"FCL\",\n \"departureDate\": \"2025-03-01\",\n \"quantity\": 1,\n \"weight\": 15000,\n \"isHazmat\": false\n}"
},
"url": {
"raw": "{{baseUrl}}/api/v1/rates/search",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"v1",
"rates",
"search"
]
},
"description": "Recherche Hamburg → Los Angeles avec conteneur 40DRY"
},
"response": []
},
{
"name": "Search Rates - With Hazmat",
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"origin\": \"NLRTM\",\n \"destination\": \"SGSIN\",\n \"containerType\": \"20DRY\",\n \"mode\": \"FCL\",\n \"departureDate\": \"2025-02-20\",\n \"quantity\": 1,\n \"weight\": 10000,\n \"isHazmat\": true,\n \"imoClass\": \"3\"\n}"
},
"url": {
"raw": "{{baseUrl}}/api/v1/rates/search",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"v1",
"rates",
"search"
]
},
"description": "Recherche avec marchandises dangereuses (Hazmat)\n\n**IMO Classes:**\n- 1: Explosifs\n- 2: Gaz\n- 3: Liquides inflammables\n- 4: Solides inflammables\n- 5: Substances comburantes\n- 6: Substances toxiques\n- 7: Matières radioactives\n- 8: Substances corrosives\n- 9: Matières dangereuses diverses"
},
"response": []
},
{
"name": "Search Rates - Invalid Port Code (Error)",
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test(\"Status code is 400 (Validation Error)\", function () {",
" pm.response.to.have.status(400);",
"});",
"",
"pm.test(\"Error message mentions validation\", function () {",
" var jsonData = pm.response.json();",
" pm.expect(jsonData).to.have.property('message');",
"});"
],
"type": "text/javascript"
}
}
],
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"origin\": \"INVALID\",\n \"destination\": \"CNSHA\",\n \"containerType\": \"40HC\",\n \"mode\": \"FCL\",\n \"departureDate\": \"2025-02-15\"\n}"
},
"url": {
"raw": "{{baseUrl}}/api/v1/rates/search",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"v1",
"rates",
"search"
]
},
"description": "Test de validation : code port invalide\n\nDevrait retourner une erreur 400 avec message de validation"
},
"response": []
}
]
},
{
"name": "Bookings API",
"description": "Gestion complète des réservations : création, consultation, listing",
"item": [
{
"name": "Create Booking",
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test(\"Status code is 201 (Created)\", function () {",
" pm.response.to.have.status(201);",
"});",
"",
"pm.test(\"Response has booking ID\", function () {",
" var jsonData = pm.response.json();",
" pm.expect(jsonData).to.have.property('id');",
" pm.expect(jsonData).to.have.property('bookingNumber');",
"});",
"",
"pm.test(\"Booking number has correct format\", function () {",
" var jsonData = pm.response.json();",
" pm.expect(jsonData.bookingNumber).to.match(/^WCM-\\d{4}-[A-Z0-9]{6}$/);",
"});",
"",
"pm.test(\"Initial status is draft\", function () {",
" var jsonData = pm.response.json();",
" pm.expect(jsonData.status).to.equal('draft');",
"});",
"",
"// Save booking ID and number for later tests",
"pm.environment.set(\"bookingId\", pm.response.json().id);",
"pm.environment.set(\"bookingNumber\", pm.response.json().bookingNumber);",
"console.log(\"Saved bookingId: \" + pm.response.json().id);",
"console.log(\"Saved bookingNumber: \" + pm.response.json().bookingNumber);"
],
"type": "text/javascript"
}
},
{
"listen": "prerequest",
"script": {
"exec": [
"// Ensure we have a rateQuoteId from previous search",
"if (!pm.environment.get(\"rateQuoteId\")) {",
" console.warn(\"No rateQuoteId found. Run 'Search Rates' first!\");",
"}"
],
"type": "text/javascript"
}
}
],
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"rateQuoteId\": \"{{rateQuoteId}}\",\n \"shipper\": {\n \"name\": \"Acme Corporation\",\n \"address\": {\n \"street\": \"123 Main Street\",\n \"city\": \"Rotterdam\",\n \"postalCode\": \"3000 AB\",\n \"country\": \"NL\"\n },\n \"contactName\": \"John Doe\",\n \"contactEmail\": \"john.doe@acme.com\",\n \"contactPhone\": \"+31612345678\"\n },\n \"consignee\": {\n \"name\": \"Shanghai Imports Ltd\",\n \"address\": {\n \"street\": \"456 Trade Avenue\",\n \"city\": \"Shanghai\",\n \"postalCode\": \"200000\",\n \"country\": \"CN\"\n },\n \"contactName\": \"Jane Smith\",\n \"contactEmail\": \"jane.smith@shanghai-imports.cn\",\n \"contactPhone\": \"+8613812345678\"\n },\n \"cargoDescription\": \"Electronics and consumer goods for retail distribution\",\n \"containers\": [\n {\n \"type\": \"40HC\",\n \"containerNumber\": \"ABCU1234567\",\n \"vgm\": 22000,\n \"sealNumber\": \"SEAL123456\"\n }\n ],\n \"specialInstructions\": \"Please handle with care. Delivery before 5 PM.\"\n}"
},
"url": {
"raw": "{{baseUrl}}/api/v1/bookings",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"v1",
"bookings"
]
},
"description": "Créer une nouvelle réservation basée sur un tarif recherché\n\n**Note:** Exécutez d'abord une recherche de tarifs pour obtenir un `rateQuoteId` valide.\n\n**Validation:**\n- Email format E.164\n- Téléphone international format\n- Country code ISO 3166-1 alpha-2 (2 lettres)\n- Container number: 4 lettres + 7 chiffres\n- Cargo description: min 10 caractères\n\n**Statuts possibles:**\n- `draft`: Initial (modifiable)\n- `pending_confirmation`: Soumis au transporteur\n- `confirmed`: Confirmé\n- `in_transit`: En transit\n- `delivered`: Livré (final)\n- `cancelled`: Annulé (final)"
},
"response": []
},
{
"name": "Get Booking by ID",
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test(\"Status code is 200\", function () {",
" pm.response.to.have.status(200);",
"});",
"",
"pm.test(\"Response has complete booking details\", function () {",
" var jsonData = pm.response.json();",
" pm.expect(jsonData).to.have.property('id');",
" pm.expect(jsonData).to.have.property('bookingNumber');",
" pm.expect(jsonData).to.have.property('shipper');",
" pm.expect(jsonData).to.have.property('consignee');",
" pm.expect(jsonData).to.have.property('rateQuote');",
"});"
],
"type": "text/javascript"
}
}
],
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{baseUrl}}/api/v1/bookings/{{bookingId}}",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"v1",
"bookings",
"{{bookingId}}"
]
},
"description": "Récupérer les détails complets d'une réservation par son ID UUID\n\n**Note:** Créez d'abord une réservation pour obtenir un `bookingId` valide."
},
"response": []
},
{
"name": "Get Booking by Booking Number",
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test(\"Status code is 200\", function () {",
" pm.response.to.have.status(200);",
"});",
"",
"pm.test(\"Booking number matches request\", function () {",
" var jsonData = pm.response.json();",
" pm.expect(jsonData.bookingNumber).to.equal(pm.environment.get(\"bookingNumber\"));",
"});"
],
"type": "text/javascript"
}
}
],
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{baseUrl}}/api/v1/bookings/number/{{bookingNumber}}",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"v1",
"bookings",
"number",
"{{bookingNumber}}"
]
},
"description": "Récupérer une réservation par son numéro (format: WCM-2025-ABC123)\n\n**Avantage:** Format plus convivial que l'UUID pour les utilisateurs"
},
"response": []
},
{
"name": "List Bookings (Paginated)",
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test(\"Status code is 200\", function () {",
" pm.response.to.have.status(200);",
"});",
"",
"pm.test(\"Response has pagination metadata\", function () {",
" var jsonData = pm.response.json();",
" pm.expect(jsonData).to.have.property('bookings');",
" pm.expect(jsonData).to.have.property('total');",
" pm.expect(jsonData).to.have.property('page');",
" pm.expect(jsonData).to.have.property('pageSize');",
" pm.expect(jsonData).to.have.property('totalPages');",
"});",
"",
"pm.test(\"Bookings is an array\", function () {",
" var jsonData = pm.response.json();",
" pm.expect(jsonData.bookings).to.be.an('array');",
"});"
],
"type": "text/javascript"
}
}
],
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{baseUrl}}/api/v1/bookings?page=1&pageSize=20",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"v1",
"bookings"
],
"query": [
{
"key": "page",
"value": "1",
"description": "Numéro de page (commence à 1)"
},
{
"key": "pageSize",
"value": "20",
"description": "Nombre d'éléments par page (max: 100)"
},
{
"key": "status",
"value": "draft",
"description": "Filtrer par statut (optionnel)",
"disabled": true
}
]
},
"description": "Lister toutes les réservations avec pagination\n\n**Paramètres de requête:**\n- `page`: Numéro de page (défaut: 1)\n- `pageSize`: Éléments par page (défaut: 20, max: 100)\n- `status`: Filtrer par statut (optionnel)\n\n**Statuts disponibles:**\n- draft\n- pending_confirmation\n- confirmed\n- in_transit\n- delivered\n- cancelled"
},
"response": []
},
{
"name": "List Bookings - Filter by Status (Draft)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{baseUrl}}/api/v1/bookings?page=1&pageSize=10&status=draft",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"v1",
"bookings"
],
"query": [
{
"key": "page",
"value": "1"
},
{
"key": "pageSize",
"value": "10"
},
{
"key": "status",
"value": "draft"
}
]
},
"description": "Lister uniquement les réservations en statut 'draft'"
},
"response": []
},
{
"name": "Create Booking - Validation Error",
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test(\"Status code is 400 (Validation Error)\", function () {",
" pm.response.to.have.status(400);",
"});",
"",
"pm.test(\"Error contains validation messages\", function () {",
" var jsonData = pm.response.json();",
" pm.expect(jsonData).to.have.property('message');",
" pm.expect(jsonData.message).to.be.an('array');",
"});"
],
"type": "text/javascript"
}
}
],
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"rateQuoteId\": \"invalid-uuid\",\n \"shipper\": {\n \"name\": \"A\",\n \"address\": {\n \"street\": \"123\",\n \"city\": \"R\",\n \"postalCode\": \"3000\",\n \"country\": \"INVALID\"\n },\n \"contactName\": \"J\",\n \"contactEmail\": \"invalid-email\",\n \"contactPhone\": \"123\"\n },\n \"consignee\": {\n \"name\": \"Test\",\n \"address\": {\n \"street\": \"123 Street\",\n \"city\": \"City\",\n \"postalCode\": \"12345\",\n \"country\": \"CN\"\n },\n \"contactName\": \"Contact\",\n \"contactEmail\": \"contact@test.com\",\n \"contactPhone\": \"+8612345678\"\n },\n \"cargoDescription\": \"Short\",\n \"containers\": []\n}"
},
"url": {
"raw": "{{baseUrl}}/api/v1/bookings",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"v1",
"bookings"
]
},
"description": "Test de validation : données invalides\n\n**Erreurs attendues:**\n- UUID invalide\n- Nom trop court\n- Email invalide\n- Téléphone invalide\n- Code pays invalide\n- Description cargo trop courte"
},
"response": []
}
]
},
{
"name": "Health & Status",
"description": "Endpoints de santé et statut du système (à implémenter)",
"item": [
{
"name": "Health Check",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{baseUrl}}/health",
"host": [
"{{baseUrl}}"
],
"path": [
"health"
]
},
"description": "Vérifier l'état de santé de l'API\n\n**Status:** À implémenter en Phase 2"
},
"response": []
}
]
}
],
"event": [
{
"listen": "prerequest",
"script": {
"type": "text/javascript",
"exec": [
""
]
}
},
{
"listen": "test",
"script": {
"type": "text/javascript",
"exec": [
""
]
}
}
],
"variable": [
{
"key": "baseUrl",
"value": "http://localhost:4000",
"type": "string"
},
{
"key": "rateQuoteId",
"value": "",
"type": "string"
},
{
"key": "bookingId",
"value": "",
"type": "string"
},
{
"key": "bookingNumber",
"value": "",
"type": "string"
}
]
}