Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create /api/v1/instance/:id/files/... api for basic CRUD operations #4357

Closed
7 tasks done
Tracked by #4194
joepavitt opened this issue Aug 9, 2024 · 4 comments · Fixed by #4384
Closed
7 tasks done
Tracked by #4194

Create /api/v1/instance/:id/files/... api for basic CRUD operations #4357

joepavitt opened this issue Aug 9, 2024 · 4 comments · Fixed by #4384
Assignees
Labels
area:api Work on the platform API size:M - 3 Sizing estimation point task A piece of work that isn't necessarily tied to a specific Epic or Story.
Milestone

Comments

@joepavitt
Copy link
Contributor

joepavitt commented Aug 9, 2024

The Frontend will make API requests to an API provided by the platform that then proxies the requests to the launcher to get the response.

As such, the semantics of the platform API will need to mirror that implemented in the launcher via FlowFuse/nr-launcher#273

  • The api will hang under /api/v1/projects/:instanceId/files/...
  • It is an EE feature; the api should only be enabled for instances in teams that have the FileManagement feature enabled
  • All operations should be available to owner and member roles - need to consider if viewer should have read-only access (ie list, but no rename/upload etc)
  • As the files are stored on the instance, this API will be unavailable if the instance is suspended.

API Endpoints

We already have a file-system-like API for the shared-library endpoints. That was largely duplicated from the Node-RED api for managing libraries. It has some drawbacks, so I don't want to blindly copy its approach.

Care must be given to (and tests to verify) handling of unexpected / \ and .. appearing in filenames/paths.

  • GET /api/v1/projects/:instanceId/files/_/:path - list files in a directory
  • PUT /api/v1/projects/:instanceId/files/_/:path - update file/directory information (name/sharing info)
  • POST /api/v1/projects/:instanceId/files/_/:path - create directory/upload file
  • DELETE /api/v1/projects/:instanceId/files/_/:path - delete directory/file

GET /api/v1/projects/:instanceId/files/_/:path

Get a directory listing of :path. The response will be a collection object and support pagination (as per https://flowfuse.com/docs/contribute/api-design/#pagination).

This doesn't provide a recursive list - only the files/directories at :path (which will be relative to /data/storage on the instance itself).

{
    "meta": {
        "next_cursor": "",
    },
    "files": [
        {
            "type": "file",
            "path": "filename",
            "size": "1024",
            "lastModified": "2024-08-08T19:40:05.000Z"
        },
        {
            "type": "directory",
            "path": "filename",
            "lastModified": "2024-08-08T19:40:05.000Z",
            "share": { ... }
        }
    ],
    "count": 8
}
  • Each entry in files has a type field to identify file vs directory.
  • file type also have size
  • directory type might also have share - meta data about how that folder is shared by Node-RED. Details below

If :path is not a directory that can be listed, the api will return 404. This means this end point cannot be used to get the file contents - that'll be handled separately.

PUT /api/v1/projects/:instanceId/files/_/:path

Update information about a file/directory. This will support the following tasks, based on the body received. This operations should be mutually exclusive.

Rename/Move

TBD: relative/absolute name

{
    path: "new filename"
}
Update sharing options

Only valid for directory objects; cannot modify sharing properties of a :path that represents a file.

{
    share: { ... }
}

POST /api/v1/projects/:instanceId/files/_/:path

Either create a directory or upload a file. I could be persuaded to separate these out somehow.. but for now...

Create directory
  • Content-type: application/json
  • Path is relative to :path and must not contain .. or /
{
    path: 'name of dir'
}
Create file
  • Content-type: multipart/form-data
  • Expect a form field called file containing the file data
  • Open questions
    • filesize limit?

DELETE /api/v1/projects/:instanceId/files/_/:path

Delete the file/directory.

share setting

The share property contains the properties:

  • root : the relative url the folder should be shared from (ref httpStatic in Node-RED configuration)

In future it can include any other settings supported by Node-RED - but root is the minimum requirement.

In the database, a new ProjectSetting will be used under the key staticAssets. This will be a single property containing information about all shared directories:

{
    "dashboard/images" : { "root": "/static/images" },
    "tps-reports" : { "root": "/reports"}
}

With the above example, an instance that is at https://nr1.example.com will serve:

  • /data/storage/dashboard/images as https://nr1.example.com/static/images
  • /data/storage/tps-reports as https://nr1.example.com/reports

So a file stored in /data/storage/dashboard/images/header/logo.png will be served as https://nr1.example.com/static/images/header/logo.png

The launcher will use this settings to set the httpStatic property of the Node-RED settings file. (PRs open for this - see task list below).

@joepavitt joepavitt moved this to In Design in 🛠 Development Aug 9, 2024
@joepavitt joepavitt added size:M - 3 Sizing estimation point area:api Work on the platform API task A piece of work that isn't necessarily tied to a specific Epic or Story. labels Aug 9, 2024
@joepavitt joepavitt added this to the 2.8 milestone Aug 9, 2024
@knolleary
Copy link
Member

Have updated the description with an initial API spec to work from. This will be the basic structure used in the launcher as well.

@joepavitt joepavitt moved this from In Design to In Progress in 🛠 Development Aug 14, 2024
@knolleary knolleary mentioned this issue Aug 15, 2024
4 tasks
@knolleary
Copy link
Member

Updated with description of the share property.

@knolleary knolleary linked a pull request Aug 16, 2024 that will close this issue
4 tasks
@joepavitt joepavitt moved this from In Progress to Review in 🛠 Development Aug 16, 2024
@hardillb
Copy link
Contributor

I think there is an error in the sample above, each file object should have name not path

{
    "meta": {
        "next_cursor": "",
    },
    "files": [
        {
            "type": "file",
            "path": "filename",
            "size": "1024",
            "lastModified": "2024-08-08T19:40:05.000Z"
        },
        {
            "type": "directory",
            "path": "filename",
            "lastModified": "2024-08-08T19:40:05.000Z",
            "share": { ... }
        }
    ],
    "count": 8
}

should be

{
    "meta": {
        "next_cursor": "",
    },
    "files": [
        {
            "type": "file",
            "name": "filename",
            "size": "1024",
            "lastModified": "2024-08-08T19:40:05.000Z"
        },
        {
            "type": "directory",
            "name": "filename",
            "lastModified": "2024-08-08T19:40:05.000Z",
            "share": { ... }
        }
    ],
    "count": 8
}

@joepavitt joepavitt moved this from Review to Done in 🛠 Development Aug 29, 2024
@joepavitt
Copy link
Contributor Author

Task Completed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:api Work on the platform API size:M - 3 Sizing estimation point task A piece of work that isn't necessarily tied to a specific Epic or Story.
Projects
Status: Done
Development

Successfully merging a pull request may close this issue.

3 participants