{
  "name": "CrudApiPut",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "PUT",
        "path": "api/messages/:id",
        "responseMode": "responseNode",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        176,
        16
      ],
      "id": "41324d87-f0b5-4876-bc5d-97f3137ad70d",
      "name": "Webhook"
    },
    {
      "parameters": {
        "queue": "Crud_Put",
        "options": {}
      },
      "type": "n8n-nodes-base.rabbitmq",
      "typeVersion": 1.1,
      "position": [
        1504,
        16
      ],
      "id": "41db0e42-6afd-4c30-b18b-720b10477363",
      "name": "RabbitMQ",
      "credentials": {
        "rabbitmq": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "{\n  \"status\": 400,\n  \"title\": \"Bad request\",\n  \"details\": \"Id is invalid or null\"\n}",
        "options": {
          "responseCode": 400
        }
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.4,
      "position": [
        1088,
        192
      ],
      "id": "878466b1-c0cc-4646-8c8e-50cc2e2f84cf",
      "name": "Respond to Webhook5"
    },
    {
      "parameters": {
        "jsCode": "const item = $input.item;\n\nif(item.json === undefined || item.json === null){\n  item.json = {};\n}\n\n\nconst crypto = require('crypto');\n\nconst secretKey = 'seu-segredo-secreto';\n\n\nfunction base64UrlDecode(data) {\n  let base64 = data.replace(/-/g, '+').replace(/_/g, '/');\n  \n  while (base64.length % 4) {\n    base64 += '=';\n  }\n  return Buffer.from(base64, 'base64').toString('utf8');\n}\n\n\ntry {\n  \n  const authHeader = $json.headers['authorization'];\n\n  if (!authHeader || !authHeader.startsWith('Bearer ')) {\n    throw new Error('Authorization header missing or invalid');\n  }\n\n \n  const token = authHeader.split(' ')[1];\n\n  \n  const [encodedHeader, encodedPayload, signature] = token.split('.');\n\n  if (!encodedHeader || !encodedPayload || !signature) {\n    throw new Error('Invalid token format');\n  }\n\n \n  const dataToSign = `${encodedHeader}.${encodedPayload}`;\n  const expectedSignature = crypto\n    .createHmac('sha256', secretKey)\n    .update(dataToSign)\n    .digest('base64url');\n\n  \n  const sigBuffer = Buffer.from(signature, 'base64url');\n  const expectedSigBuffer = Buffer.from(expectedSignature, 'base64url');\n\n  if (sigBuffer.length !== expectedSigBuffer.length || !crypto.timingSafeEqual(sigBuffer, expectedSigBuffer)) {\n    throw new Error('Invalid signature');\n  }\n\n  \n  const payload = JSON.parse(base64UrlDecode(encodedPayload));\n  const nowInSeconds = Math.floor(Date.now() / 1000);\n\n  if (payload.exp < nowInSeconds) {\n    throw new Error('Token has expired');\n  }\n\n \n  item.json.auth_user = payload;\n  item.json.isValid = true;\n\n} catch (Error) {\n\n  item.json.isValid = false;\n  item.json.errorDetails = Error.message;\n}\n\nreturn item;"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        320,
        16
      ],
      "id": "2c153710-740d-4652-9b48-c72deae65eb5",
      "name": "token_Validation",
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "953bbc3b-1c4c-47eb-bd04-bf466211ddf1",
              "leftValue": "={{ $json.isValid }}",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        512,
        16
      ],
      "id": "175ffa9a-0d7a-4d97-b4ca-77794e181c1d",
      "name": "token_Is_Valid"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "{\n  \"type\": \"https://example.com/probs/internal-error\",\n  \"title\": \"Internal Server Error\",\n  \"status\": 500,\n  \"detail\": \"Ocorreu um erro interno inesperado ao processar sua solicita\u00e7\u00e3o.\",\n  \"instance\": \"/api/messages/:id\",\n  \"request_id\": \"req_xyz987\"\n}",
        "options": {
          "responseCode": 500
        }
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.4,
      "position": [
        512,
        192
      ],
      "id": "63a50d34-ab9c-4a77-a1be-084b705ed76b",
      "name": "error_500"
    },
    {
      "parameters": {
        "jsCode": "const uuidRegex = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;\n\nconst returnItems = [];\n\nfor (const item of $input.all()) {\n  try {\n    if (item.json === undefined || item.json === null) {\n      item.json = {};\n    }\n    \n    const id = item.json.params.id;\n    \n    if (!id || !uuidRegex.test(id)) {\n      item.json.id_validation_error = {\n          type: \"https://example.com/probs/invalid-parameter\",\n          title: \"Invalid Parameter\",\n          status: 400, \n          detail: \"The 'id' parameter in the URL is missing or not a valid UUID.\",\n          instance: item.json.webhookUrl || 'webhookUrl_not_found'\n      };\n    } else {\n      item.json.id_validation_error = null;\n    }\n    \n  } catch (error) {\n    item.json.id_validation_error = {\n        type: \"https://example.com/probs/internal-error\",\n        title: \"Internal Server Error\",\n        status: 500,\n        detail: \"An unexpected error occurred during ID validation: \" + error.message\n    };\n  }\n  \n  returnItems.push(item);\n}\n\nreturn returnItems;"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        720,
        16
      ],
      "id": "5f63b464-9e25-47e8-88db-31f8155a5753",
      "name": "id_Validation",
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "{\n\"title\": \"unauthorized\",\n\"status\": 401,\n\"detail\": \"invalid or expired token\"\n}",
        "options": {
          "responseCode": 401
        }
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.4,
      "position": [
        720,
        192
      ],
      "id": "49ecccc2-4066-4dc6-be41-58ef188d9d09",
      "name": "error_401"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "b0f6aaeb-31b6-4938-95fc-96aa583810a9",
              "leftValue": "={{ $json.id_validation_error }}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        912,
        16
      ],
      "id": "cf5966bc-f453-4517-bb9e-2bcaf848f467",
      "name": "id_Validation_Error_Is_Not_Empty"
    },
    {
      "parameters": {
        "jsCode": "\nconst returnItems = [];\n\n\nfor (const item of $input.all()) {\n  try {\n    if (item.json === undefined || item.json === null) {\n      item.json = {};\n    }\n\n    const body = item.json.body || {};\n\n    const invalid_params = [];\n    const validated_data = {};\n\n    if (!body.title) {\n        invalid_params.push({ name: 'title', reason: 'required' });\n    } else if (typeof body.title !== 'string') {\n        invalid_params.push({ name: 'title', reason: 'must be a string' });\n    } else if (body.title.trim().length === 0) {\n        invalid_params.push({ name: 'title', reason: 'must not be empty' });\n    } else {\n        validated_data.title = body.title.trim();\n    }\n\n    if (!body.body) {\n        invalid_params.push({ name: 'body', reason: 'required' });\n    } else if (typeof body.body !== 'string') {\n        invalid_params.push({ name: 'body', reason: 'must be a string' });\n    } else if (body.body.length < 1) {\n        invalid_params.push({ name: 'body', reason: 'must be at least 1 character long' });\n    } else {\n        validated_data.body = body.body;\n    }\n\n    if (body.author !== undefined && body.author !== null) {\n        if (typeof body.author !== 'string') {\n            invalid_params.push({ name: 'author', reason: 'must be a string' });\n        } else {\n            validated_data.author = body.author;\n        }\n    } else {\n        validated_data.author = null; \n    }\n\n    const valid_statuses = ['draft', 'published', 'archived'];\n    if (body.status !== undefined && body.status !== null) {\n        if (typeof body.status !== 'string' || !valid_statuses.includes(body.status)) {\n            invalid_params.push({ name: 'status', reason: 'must be one of: draft, published, archived' });\n        } else {\n            validated_data.status = body.status;\n        }\n    } else {\n        validated_data.status = 'draft';\n    }\n\n    if (invalid_params.length > 0) {\n        const problem_json = {\n            type: \"https://example.com/probs/invalid-input\",\n            title: \"Invalid input\",\n            status: 400,\n            detail: \"One or more fields failed validation\",\n            instance: item.json.webhookUrl || 'webhookUrl_not_found', \n            invalid_params: invalid_params\n        };\n        item.json.validation_error = problem_json;\n        item.json.validated_data = null;\n    } else {\n        item.json.validation_error = null;\n        item.json.validated_data = validated_data;\n    }\n\n  } catch (error) {\n      if (item.json === undefined || item.json === null) {\n        item.json = {};\n      }\n      item.json.validation_error = {\n        type: \"https://example.com/probs/internal-error\",\n        title: \"Internal Server Error\",\n        status: 500,\n        detail: \"An unexpected error occurred during payload validation.\"\n      };\n      item.json.payload_error_details = error.message;\n  }\n  \n  returnItems.push(item);\n}\n\nreturn returnItems;"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1088,
        16
      ],
      "id": "eb970375-b9e6-4692-befb-0fdb0ad5cac4",
      "name": "pay_load_Validation",
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "2e24857b-370e-44d6-9123-b45a72dee74f",
              "leftValue": "={{ $json.validation.error }}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1280,
        16
      ],
      "id": "018474a0-feb9-4653-a4f5-4003466b5de1",
      "name": "validation_Error_Is_Not_Empty"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "{\n  \"type\": \"https://example.com/probs/internal-error\",\n  \"title\": \"Internal Server Error\",\n  \"status\": 500,\n  \"detail\": \"Ocorreu um erro interno inesperado ao processar sua solicita\u00e7\u00e3o.\",\n  \"instance\": \"/api/messages/:id\",\n  \"request_id\": \"req_xyz987\"\n}",
        "options": {
          "responseCode": 500
        }
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.4,
      "position": [
        912,
        192
      ],
      "id": "cdcd21f1-8217-4dd1-ac63-20e8494fb79c",
      "name": "error_500_"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "{\n  \"type\": \"https://example.com/probs/internal-error\",\n  \"title\": \"Internal Server Error\",\n  \"status\": 500,\n  \"detail\": \"Ocorreu um erro interno inesperado ao processar sua solicita\u00e7\u00e3o.\",\n  \"instance\": \"/api/messages/:id\",\n  \"request_id\": \"req_xyz987\"\n}",
        "options": {
          "responseCode": 500
        }
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.4,
      "position": [
        1280,
        192
      ],
      "id": "e5027d08-12f4-4737-97af-b4a108f00759",
      "name": "_error_500"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "{\n  \"type\": \"https://example.com/probs/invalid-input\",\n  \"title\": \"Invalid input\",\n  \"status\": 400,\n  \"detail\": \"One or more fields failed validation\",\n  \"instance\": \"/api/messages/:id\"\n}",
        "options": {
          "responseCode": 400
        }
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.4,
      "position": [
        1504,
        192
      ],
      "id": "9018e90c-0686-444b-bb22-68478ff4d72b",
      "name": "error_400"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "{\n  \"status\": 202,\n  \"title\": \"accepted\"\n}",
        "options": {
          "responseCode": 202
        }
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.4,
      "position": [
        1712,
        16
      ],
      "id": "5efd1714-1776-484e-840d-a0c61f541aa8",
      "name": "accepted_202"
    }
  ],
  "connections": {
    "Webhook": {
      "main": [
        [
          {
            "node": "token_Validation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "RabbitMQ": {
      "main": [
        [
          {
            "node": "accepted_202",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "token_Validation": {
      "main": [
        [
          {
            "node": "token_Is_Valid",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "error_500",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "token_Is_Valid": {
      "main": [
        [
          {
            "node": "id_Validation",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "error_401",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "id_Validation": {
      "main": [
        [
          {
            "node": "id_Validation_Error_Is_Not_Empty",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "error_500_",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "id_Validation_Error_Is_Not_Empty": {
      "main": [
        [
          {
            "node": "Respond to Webhook5",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "pay_load_Validation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "pay_load_Validation": {
      "main": [
        [
          {
            "node": "validation_Error_Is_Not_Empty",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "_error_500",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "validation_Error_Is_Not_Empty": {
      "main": [
        [
          {
            "node": "error_400",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "RabbitMQ",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "c47c113e-0311-439e-8795-bb07b53cb0b9",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "id": "g78ahm6xty1YHSA3",
  "tags": []
}