Skip to content

Xkonti/file-api

Repository files navigation

File API

A simple RESTful API that allows you to manipulate files and directories.

Warning

This project is in early development stage.

Important

💀 There are no robust protections against malicious users. This API is intended to be used as an internal API for simple projects. Usage of a service mesh that encrypts traffic between services is recommended.

Usage

Running in Docker

The easiest way to run the File API is to use the Docker image. The image is available on Docker Hub:

docker run -d \
  -p 3210:3000 \
  -e API_KEY=YOUR_API_KEY \
  -v /your/directory/to/mount:/data:rw \
  xkonti/file-api:latest

Available configuration options:

  • Internal port: 3000
  • Mount point for the directory to be managed via API: /data
  • API_KEY environment variable: the API key to use for authentication

Authentication

An API key must be configured in order to use the API. The API key can be configured using the API_KEY environment variable. Please use something that is base64 encoded so that it can be used in HTTP headers and URL query.

Each HTTP request will be first checked for API key. If the API key is not provided, the request will be rejected with a 401 Unauthorized response. The API key can be provided in two ways:

  • HTTP header: api-key - example: curl --request GET --url 'http://localhost:3000/list?path=%2F' --header 'apikey: YOUR_API_KEY'
  • Query parameter: apikey - example: curl --request GET --url 'http://localhost:3000/list?path=%2F&apikey=YOUR_API_KEY'

API

List files and directories in a directory

You can list files and/or directories by using the GET /list endpoint with the following query parameters:

  • path - the path of the directory to list (remember to url-encode it)
  • dirs - whether to include directories or not (default: false). If directories are listed their contents will be nested.
  • depth - how deep to list directories. The default 1 will list only files and directories within the specified directory - no contents of subdirectories will be listed.
Examples [click to expand]
  • curl --request GET --url 'http://localhost:3000/list?path=%2F' - list only files in the root directory (%2F is the encoded /):

    [
      {
        "name": "Expenses 2022.xlsx",
        "fullPath": "/Expenses 2022.xlsx",
        "type": "file"
      }
    ]
  • curl --request GET --url 'http://localhost:3000/list?path=%2F&dirs=true' - list files and directories in the root directory (%2F is the encoded /):

    [
      {
        "name": "repos",
        "fullPath": "/repos",
        "type": "dir"
      },
      {
        "name": "Expenses 2022.xlsx",
        "fullPath": "/Expenses 2022.xlsx",
        "type": "file"
      }
    ]
  • curl --request GET --url 'http://localhost:3000/list?path=%2F&dirs=true&depth=2' - list files and directories in the root directory. Additionally increase depth to 2 so that the contents of the repos directory are listed:

    [
      {
        "name": "repos",
        "fullPath": "/repos",
        "type": "dir",
        "contents": [
          {
            "name": "rusty-result-ts",
            "fullPath": "/repos/rusty-result-ts",
            "type": "dir"
          },
          {
            "name": "vue-smart-routes",
            "fullPath": "/repos/vue-smart-routes",
            "type": "dir"
          },
          {
            "name": "todo.md",
            "fullPath": "/repos/todo.md",
            "type": "file"
          },
          {
            "name": "clean-node-package-typescript",
            "fullPath": "/repos/clean-node-package-typescript",
            "type": "dir"
          },
          {
            "name": "notes.md",
            "fullPath": "/repos/notes.md",
            "type": "file"
          }
        ]
      },
      {
        "name": "Expenses 2022.xlsx",
        "fullPath": "/Expenses 2022.xlsx",
        "type": "file"
      }
    ]
  • curl --request GET --url 'http://localhost:3000/list?path=%2F&dirs=true&depth=2' - list only files in the root directory. Additionally increase depth to 2 so that the contents of the repos directory are listed. This will present all the files as a flat list:

    [
      {
        "name": "todo.md",
        "fullPath": "/repos/todo.md",
        "type": "file"
      },
      {
        "name": "notes.md",
        "fullPath": "/repos/notes.md",
        "type": "file"
      },
      {
        "name": "Expenses 2022.xlsx",
        "fullPath": "/Expenses 2022.xlsx",
        "type": "file"
      }
    ]
  • curl --request GET --url 'http://localhost:3000/list?path=repos%2Frusty-result.ts&dirs=true' - list files and directories in the repos/rusty-result.ts directory. Additionally increase depth to 2 so that the contents of the repos directory are listed:

    [
      {
        "name": "repos",
        "fullPath": "/repos",
        "type": "dir",
        "contents": [
          {
            "name": "rusty-result-ts",
            "fullPath": "/repos/rusty-result-ts",
            "type": "dir"
          },
          {
            "name": "vue-smart-routes",
            "fullPath": "/repos/vue-smart-routes",
            "type": "dir"
          },
          {
            "name": "todo.md",
            "fullPath": "/repos/todo.md",
            "type": "file"
          },
          {
            "name": "clean-node-package-typescript",
            "fullPath": "/repos/clean-node-package-typescript",
            "type": "dir"
          },
          {
            "name": "notes.md",
            "fullPath": "/repos/notes.md",
            "type": "file"
          }
        ]
      },
      {
        "name": "Expenses 2022.xlsx",
        "fullPath": "/Expenses 2022.xlsx",
        "type": "file"
      }
    ]

Download a file

You can download a specific file by using the GET /file endpoint with the following query parameters:

  • path - the path of the file to download (remember to url-encode it)

If the file does not exist or a path is pointing to a directory, a 404 Not Found response will be returned.

Examples [click to expand]
  • curl --request GET --url 'http://localhost:3000/file?path=%2FExpenses%202022.xlsx' - download the Expenses 2022.xlsx file (%2FExpenses%202022.xlsx is the encoded /Expenses 2022.xlsx)

Upload a file

You can upload a specific file by using the POST /file endpoint with the following query parameters:

  • path - the destination path of the file to upload (remember to url-encode it)
  • overwrite - whether to overwrite the file if it already exists (default: false)

All the parent directories of the destination path will be created automatically if they do not exist.

The file contents should be sent in the request body in one of the following ways:

  • multipart/form-data - the file contents should be sent as a file field
  • application/octet-stream - the file contents should be sent as the request body

Possible responses:

  • 201 - the file was uploaded successfully
  • 400 - the request was malformed in some way:
    • the path parameter is missing
    • the path parameter is pointing to a directory
    • the file contents are missing
  • 415 - unsupported content type
  • 422 - unrecognized file contents format
Examples [click to expand]
  • curl --request POST --url 'http://localhost:3000/file?path=%2FExpenses%202022.xlsx' --header 'Content-Type: application/octet-stream' --data-binary @/path/to/file - upload the Expenses 2022.xlsx file (%2FExpenses%202022.xlsx is the encoded /Expenses 2022.xlsx)

Check if file exists

You can check if a specific file exists by using the GET /file/exists endpoint with the following query parameters:

  • path - the path of the file to check (remember to url-encode it)

Possible responses:

  • 204 - the file exists
  • 404 - the file does not exist
  • 400 - the request was malformed in some way:
    • the path parameter is missing
    • the path parameter is pointing to a directory

Get file size

You can get the size of a specific file by using the GET /file/size endpoint with the following query parameters:

  • path - the path of the file to check (remember to url-encode it)

Possible responses:

  • 200 - the file exists and the size is returned in the response body
  • 404 - the file does not exist
  • 400 - the request was malformed in some way:
    • the path parameter is missing
    • the path parameter is pointing to a directory

Response body with file size in bytes:

{
  "size": 123456
}

Roadmap

Directories

  • List files and directories in a directory as a flat list: GET /list
  • List files and directories in a directory as a tree: GET /tree
  • Check if a directory exists: GET /dir/exists
  • Create a directory: POST /dir
  • Delete a directory: DELETE /dir
  • Rename a directory: : POST /dir/rename
  • Move a directory: POST /dir/move
  • Copy a directory: POST /dir/copy

Files

  • Check if a file exists: GET /file/exists
  • Download a file: GET /file
  • Upload a file: POST /file
  • Delete a file: DELETE /file
  • Create an empty file: POST /file/touch
  • Rename a file: POST /file/rename
  • Move a file: POST /file/move
  • Copy a file: POST /file/copy
  • Get file metadata: GET /file/meta
  • Get file size: GET /file/size

Permissions

  • API key authentication
  • Protect paths with API keys
  • Protect operation categories with API keys
    • Listing files and directories
    • Downloading files
    • Uploading/copying files & creating directories
    • Deleting/moving/renaming files & directories

Deployment

  • Docker image on Docker Hub
  • Docker image on GitHub Container Registry
  • CI/CD pipeline using GitHub Actions and Dagger

Stack