feat(api): add file listing endpoint
- Add GET /api endpoint to list all markdown files - Filter to only include .md files - Return JSON response with files array - Add comprehensive tests for file listing functionality
This commit is contained in:
@@ -38,10 +38,36 @@ func (h *APIHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
func (h *APIHandler) handleListFiles(w http.ResponseWriter, r *http.Request) {
|
||||
h.log.Info("GET request for file listing")
|
||||
|
||||
files, err := os.ReadDir(h.dataDir)
|
||||
if err != nil {
|
||||
h.log.Errorf("Error reading data directory: %v", err)
|
||||
h.writeError(w, http.StatusInternalServerError, "failed to list files")
|
||||
return
|
||||
}
|
||||
|
||||
filenames := []string{}
|
||||
for _, file := range files {
|
||||
if !file.IsDir() && filepath.Ext(file.Name()) == ".md" {
|
||||
filenames = append(filenames, file.Name())
|
||||
}
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(map[string][]string{"files": filenames})
|
||||
}
|
||||
|
||||
func (h *APIHandler) handleGet(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
filename := vars["filename"]
|
||||
|
||||
if filename == "" {
|
||||
h.handleListFiles(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
h.log.Infof("GET request for file: %s", filename)
|
||||
|
||||
filepath := filepath.Join(h.dataDir, filename)
|
||||
|
||||
@@ -31,6 +31,7 @@ func NewServer(host string, port int, handler http.Handler, log *logrus.Logger)
|
||||
|
||||
func (s *Server) Start() error {
|
||||
router := mux.NewRouter()
|
||||
router.Handle("/api", s.handler).Methods("GET")
|
||||
router.Handle("/api/{filename:.+.md}", s.handler)
|
||||
router.PathPrefix("/").Handler(http.FileServer(http.Dir("frontend/dist")))
|
||||
|
||||
|
||||
141
backend/tests/file_listing_test.go
Normal file
141
backend/tests/file_listing_test.go
Normal file
@@ -0,0 +1,141 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/evanreichard/markdown-editor/internal/api"
|
||||
"github.com/evanreichard/markdown-editor/internal/logger"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestFileListing(t *testing.T) {
|
||||
dataDir, err := setupTestDir()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create test dir: %v", err)
|
||||
}
|
||||
defer cleanupTestDir(dataDir)
|
||||
|
||||
// Create some test files
|
||||
testFiles := []string{
|
||||
"file1.md",
|
||||
"file2.md",
|
||||
"file3.md",
|
||||
}
|
||||
|
||||
for _, filename := range testFiles {
|
||||
filepath := filepath.Join(dataDir, filename)
|
||||
content := "# " + filename + "\n\nContent of " + filename
|
||||
if err := os.WriteFile(filepath, []byte(content), 0644); err != nil {
|
||||
t.Fatalf("Failed to create test file %s: %v", filename, err)
|
||||
}
|
||||
}
|
||||
|
||||
log := logger.NewLogger()
|
||||
handler := api.NewAPIHandler(dataDir, log)
|
||||
router := mux.NewRouter()
|
||||
router.Handle("/api", handler).Methods("GET")
|
||||
router.Handle("/api/{filename:.+\\.md}", handler)
|
||||
|
||||
// Test GET /api (list files)
|
||||
req := httptest.NewRequest("GET", "/api", nil)
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
|
||||
var response struct {
|
||||
Files []string `json:"files"`
|
||||
}
|
||||
body, _ := io.ReadAll(w.Body)
|
||||
assert.NoError(t, json.Unmarshal(body, &response))
|
||||
|
||||
// Verify all test files are returned
|
||||
assert.Len(t, response.Files, 3)
|
||||
assert.Contains(t, response.Files, "file1.md")
|
||||
assert.Contains(t, response.Files, "file2.md")
|
||||
assert.Contains(t, response.Files, "file3.md")
|
||||
}
|
||||
|
||||
func TestFileListingWithNonMarkdownFiles(t *testing.T) {
|
||||
dataDir, err := setupTestDir()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create test dir: %v", err)
|
||||
}
|
||||
defer cleanupTestDir(dataDir)
|
||||
|
||||
// Create test files including non-markdown files
|
||||
testFiles := []string{
|
||||
"file1.md",
|
||||
"file2.txt",
|
||||
"file3.md",
|
||||
"file4.log",
|
||||
}
|
||||
|
||||
for _, filename := range testFiles {
|
||||
filepath := filepath.Join(dataDir, filename)
|
||||
content := "Content of " + filename
|
||||
if err := os.WriteFile(filepath, []byte(content), 0644); err != nil {
|
||||
t.Fatalf("Failed to create test file %s: %v", filename, err)
|
||||
}
|
||||
}
|
||||
|
||||
log := logger.NewLogger()
|
||||
handler := api.NewAPIHandler(dataDir, log)
|
||||
router := mux.NewRouter()
|
||||
router.Handle("/api", handler).Methods("GET")
|
||||
router.Handle("/api/{filename:.+\\.md}", handler)
|
||||
|
||||
// Test GET /api (list files)
|
||||
req := httptest.NewRequest("GET", "/api", nil)
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
|
||||
var response struct {
|
||||
Files []string `json:"files"`
|
||||
}
|
||||
body, _ := io.ReadAll(w.Body)
|
||||
assert.NoError(t, json.Unmarshal(body, &response))
|
||||
|
||||
// Verify only markdown files are returned
|
||||
assert.Len(t, response.Files, 2)
|
||||
assert.Contains(t, response.Files, "file1.md")
|
||||
assert.Contains(t, response.Files, "file3.md")
|
||||
assert.NotContains(t, response.Files, "file2.txt")
|
||||
assert.NotContains(t, response.Files, "file4.log")
|
||||
}
|
||||
|
||||
func TestFileListingEmptyDirectory(t *testing.T) {
|
||||
dataDir, err := setupTestDir()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create test dir: %v", err)
|
||||
}
|
||||
defer cleanupTestDir(dataDir)
|
||||
|
||||
log := logger.NewLogger()
|
||||
handler := api.NewAPIHandler(dataDir, log)
|
||||
router := mux.NewRouter()
|
||||
router.Handle("/api", handler).Methods("GET")
|
||||
router.Handle("/api/{filename:.+\\.md}", handler)
|
||||
|
||||
// Test GET /api (list files in empty directory)
|
||||
req := httptest.NewRequest("GET", "/api", nil)
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
|
||||
var response struct {
|
||||
Files []string `json:"files"`
|
||||
}
|
||||
body, _ := io.ReadAll(w.Body)
|
||||
assert.NoError(t, json.Unmarshal(body, &response))
|
||||
|
||||
// Verify empty array is returned
|
||||
assert.Len(t, response.Files, 0)
|
||||
}
|
||||
Reference in New Issue
Block a user