rest.nvim icon indicating copy to clipboard operation
rest.nvim copied to clipboard

Feature: export Requests to cURL commands

Open sahaj-b opened this issue 9 months ago • 3 comments

Issues

  • [x] I have checked existing issues and there are no existing ones with the same request.

Feature description

It would be great to have an option to export requests from a .http file to a cURL command format, similar to the functionality provided by the intelij Idea HTTP client.

As many clients like Postman supports importing curl commands, this can allow converting .http files as collections for other clients with scripts, thus can be shared

Would be cool if we can import curl commands as .http files too

sahaj-b avatar Feb 20 '25 14:02 sahaj-b

Exporting http to curl command format is already builtin as experimental :Rest curl yank and :Rest curl comment commands. For importing curl commands as http format, #415 might address that issue (I haven't work on it for a while, but I'll get back to it soon)

boltlessengineer avatar Feb 21 '25 02:02 boltlessengineer

Made this script for converting the whole file into curl commands, utilizing rest-nvim.client.curl.cli command builder

Script
local function getEnvVars()
  local dotenv = require("rest-nvim.parser.dotenv")
  local env_file = vim.b._rest_nvim_env_file
  local envVars = {}
  if env_file then
    local ok, vars = dotenv.parse(env_file)
    if ok then
      envVars = vars
    else
      vim.schedule(function()
        vim.notify("Failed to load environment file: " .. env_file, vim.log.levels.WARN)
      end)
    end
  end
  return envVars
end

local function applySubstitutions(lines, useEnvVars)
  if useEnvVars then
    local env = getEnvVars()
    if env then
      for i, line in ipairs(lines) do
        for k, v in pairs(env) do
          line = line:gsub("{{" .. k .. "}}", v)
        end
        lines[i] = line
      end
    end
  else
    for i, line in ipairs(lines) do
      -- escape brackets so the request parser doesn't remove them
      line = line:gsub("{{", "\\{\\{"):gsub("}}", "\\}\\}")
      lines[i] = line
    end
  end
  return lines
end

local function extractCurlCommands(useEnvVars, format)
  local parser = require("rest-nvim.parser")
  local builder = require("rest-nvim.client.curl.cli").builder

  local originalBuf = vim.api.nvim_get_current_buf()
  local originalLines = vim.api.nvim_buf_get_lines(originalBuf, 0, -1, false)

  vim.cmd("vnew")
  local scratchBuf = vim.api.nvim_get_current_buf()

  local modifiedLines = applySubstitutions(originalLines, useEnvVars)
  vim.api.nvim_buf_set_lines(scratchBuf, 0, -1, false, modifiedLines)

  local nodes = parser.get_all_request_nodes()
  print("Extracting " .. #nodes .. " requests to curl commands")
  local output = {}

  for _, node in ipairs(nodes) do
    local request = parser.parse(node, 0)
    request.cookies = {}

    if request.body and request.body.__TYPE == "json" and (not request.headers or not request.headers["content-type"]) then
      request.headers = request.headers or {}
      request.headers["content-type"] = { "application/json" }
    end

    table.insert(output, "# " .. request.name)
    local curlCmd = builder.build_command(request)
    curlCmd = curlCmd:gsub("%-sL", "-L")
    if not useEnvVars then
      -- revert the escaping for the final output.
      curlCmd = curlCmd:gsub("\\{\\{", "{{"):gsub("\\}\\}", "}}")
    end

    if format then
      for _, line in ipairs(vim.split(curlCmd, "\n", true)) do
        table.insert(output, line)
      end
    else
      curlCmd = curlCmd:gsub("\n", " ")
      table.insert(output, curlCmd)
    end
    table.insert(output, "")
  end

  -- replace scratchpad content with the curl commands
  vim.api.nvim_buf_set_lines(scratchBuf, 0, -1, false, output)
  vim.bo.filetype = "sh"
end

vim.api.nvim_create_user_command("ExtractCommands", function(opts)
  local unformatted = (opts.args == "compact")
  extractCurlCommands(true, not unformatted)
end, { nargs = "?" })

vim.api.nvim_create_user_command("ExtractCommandsVar", function(opts)
  local unformatted = (opts.args == "compact")
  extractCurlCommands(false, not unformatted)
end, { nargs = "?" })

Example usage:

:ExtractCommands -> extracts all curl commands (formatted json) with variables replaced :ExtractCommandsVar compact-> extracts all curl commands (without formatting) without variable substitution

I couldn't get rest-nvim.parser to automatically replace environment variables, I think it's because I don't pass the context argument to the parser, and I don't know how to get the current context

The output can be used to convert to, for example, postman collections with multiple-curl-to-postman

sahaj-b avatar Feb 22 '25 11:02 sahaj-b

Workaround for importing curl format to http: see the bash script curlToHttp.sh mentioned here https://github.com/rest-nvim/rest.nvim/issues/144#issuecomment-2676292472

sahaj-b avatar Feb 22 '25 16:02 sahaj-b