> ## Content Index
> Fetch the complete content index at: https://articles.akadata.co.uk/llms.txt
> Use this file to discover other available public pages before exploring further.

# Transforming Any Command-Line App into a Remote API
- URL: https://articles.akadata.co.uk/transforming-any-command-line-app-into-a-remote-api/
- Published: 2025-02-21T12:12:06.000Z
- Updated: 2025-02-21T12:14:32.000Z
- Author: AKADATA

## **Introduction**

Not all software starts with an API, but any command-line tool can be turned into a remote-access API within **days** with the right approach. Whether it's an image processor, data analysis tool, or astronomical plate solver like in our example, wrapping command-line applications with an API allows for **web-based automation, remote access, and integration with modern platforms**.

This article walks through the process of turning a **command-line application into an API**, using Go and a simple HTTP server to expose command execution over the web.

## **Why Turn a CLI App into an API?**

✅ **Enable Remote Access** – Run the application from anywhere, not just on a local machine.   
✅ **Scalability** – Allow multiple users or systems to interact with the tool simultaneously.   
✅ **Automation & Integration** – Integrate with other services, like web apps, AI pipelines, or cloud computing workflows.   
✅ **Modernization** – Upgrade legacy tools without rewriting them from scratch.

## **Example: Exposing a Plate Solver via an API**

The following Go-based implementation takes an existing **command-line plate solver** and turns it into an API that can be accessed remotely.

### **Step 1: Create an HTTP Server in Go**

First, we set up a basic HTTP server that listens for requests and executes the command-line tool.

```go
package main

import (
    "fmt"
    "log"
    "net/http"
    "os/exec"
)

// API handler to process an image with the CLI tool
func solveHandler(w http.ResponseWriter, r *http.Request) {
    // Extract parameters from request
    imageFile := r.URL.Query().Get("image")
    if imageFile == "" {
        http.Error(w, "Missing image parameter", http.StatusBadRequest)
        return
    }
    
    // Construct the CLI command
    cmd := exec.Command("./platesolver", "-f", imageFile)
    output, err := cmd.CombinedOutput()
    if err != nil {
        http.Error(w, fmt.Sprintf("Error executing solver: %s", err), http.StatusInternalServerError)
        return
    }
    
    // Return solver output
    fmt.Fprintf(w, "%s", output)
}

func main() {
    http.HandleFunc("/solve", solveHandler)
    fmt.Println("Server is running on port 8080...")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

```

### **Step 2: Running the API Server**

Compile and run the Go server:

```sh
go build -o api_server main.go
./api_server

```

### **Step 3: Sending Requests to the API**

Once the server is running, send a request to process an image with the CLI tool:

```sh
curl "http://localhost:8080/solve?image=test.fits"

```

The server will execute `./platesolver -f test.fits` and return the output.

## **Expanding Functionality**

### **Handling File Uploads**

Instead of passing filenames, the API can accept file uploads and process them before execution.

```go
func uploadHandler(w http.ResponseWriter, r *http.Request) {
    file, _, err := r.FormFile("image")
    if err != nil {
        http.Error(w, "Failed to read file", http.StatusBadRequest)
        return
    }
    defer file.Close()
    
    tempFile, err := os.CreateTemp("./uploads", "upload-*.fits")
    if err != nil {
        http.Error(w, "Failed to save file", http.StatusInternalServerError)
        return
    }
    defer tempFile.Close()
    
    io.Copy(tempFile, file)
    fmt.Fprintf(w, "File uploaded: %s", tempFile.Name())
}

```

### **Adding Authentication**

To secure the API, **API keys or JWT tokens** can be used to restrict access.

```go
func authMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        apiKey := r.Header.Get("X-API-KEY")
        if apiKey != "your-secret-key" {
            http.Error(w, "Unauthorized", http.StatusUnauthorized)
            return
        }
        next.ServeHTTP(w, r)
    })
}

```

## **Conclusion**

By wrapping command-line tools with a lightweight API, legacy applications can be **modernized and accessed remotely** without modifying their core functionality. This approach enables **scalability, automation, and cloud integration** while keeping development time minimal.

🚀 **Looking to convert your CLI tool into a web API?** AKADATA can help you build scalable solutions quickly!