Transforming Any Command-Line App into a Remote API

Transforming Any Command-Line App into a Remote API

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.

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:

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:

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.

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.

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!