{
  "name": "CrudApiPost",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "api/messages",
        "responseMode": "responseNode",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        0,
        0
      ],
      "id": "03b9ba40-6896-4279-bb33-5397e7dec9f1",
      "name": "Webhook"
    },
    {
      "parameters": {
        "queue": "Crud_Post",
        "options": {}
      },
      "type": "n8n-nodes-base.rabbitmq",
      "typeVersion": 1.1,
      "position": [
        1008,
        -96
      ],
      "id": "41ef65a7-128d-487a-84ea-c5928c46a674",
      "name": "RabbitMQ",
      "credentials": {
        "rabbitmq": {
          "name": "<your credential>"
        }
      }
    },
    {
      "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\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": [
        192,
        0
      ],
      "id": "b2b14595-e504-4230-a221-a4db4ea6ac7f",
      "name": "token_Validation",
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "0098e0ad-2cfe-4bb4-9329-c04e87ae2426",
              "leftValue": "={{ $json.isValid }}",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        432,
        -96
      ],
      "id": "b1b7ec60-a699-4949-9682-76999c107477",
      "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\",\n  \"request_id\": \"req_xyz987\"\n}",
        "options": {
          "responseCode": 500
        }
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.4,
      "position": [
        432,
        128
      ],
      "id": "7c8ab678-c241-4c48-a0f1-5ec4d0f5e632",
      "name": "error_500"
    },
    {
      "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": [
        624,
        128
      ],
      "id": "05e6627d-dfc7-432d-a55e-a51efe1a7cd8",
      "name": "error_401"
    },
    {
      "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\",\n  \"request_id\": \"req_xyz987\"\n}",
        "options": {
          "responseCode": 500
        }
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.4,
      "position": [
        816,
        128
      ],
      "id": "52a9a9ae-5e41-4935-82f7-a2c50afefc39",
      "name": "error_500_"
    },
    {
      "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": [
        624,
        -96
      ],
      "id": "c908b9ec-da48-42b2-b5bd-f446dd97f57a",
      "name": "payload_Validation",
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "a190cf7a-86cd-4543-bfc6-c39d73b6aece",
              "leftValue": "={{ $json.validation.error }}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        816,
        -96
      ],
      "id": "3616f0a7-631a-491e-8529-8ee44f029384",
      "name": "validation_Error_Is_Not_Empty"
    },
    {
      "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\"\n}",
        "options": {
          "responseCode": 400
        }
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.4,
      "position": [
        1008,
        128
      ],
      "id": "91df6e0d-ad9f-418c-826a-790f985d2e4a",
      "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": [
        1216,
        -96
      ],
      "id": "959679b6-3df4-4546-99dc-fa188e0314ab",
      "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": "payload_Validation",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "error_401",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "payload_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": "d2d8ccd7-2fff-4ea9-921e-1282a5f8b502",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "id": "opf15ckuvWtyIwD8",
  "tags": []
}