GSoC: Designing API

April 27, 2016

One of the most important tasks for my project is to design the API right. That’s something I would start with, so if there are any mistakes or wrong decisions, I’d be suffering from those later. Of course, I don’t want to suffer or rewrite the API over and over again, so I should think it through.

I already mentioned I wrote a small prototype, which uses Dropbox API and has simple sync feature. I actually thought I should write prototypes for all cloud providers I’m going to add support of, so I get experience of using those. That would help me find common parts and differences, and with all this experience I would be ready to design a good API — considering all pitfalls I met writing prototypes.

But a few days back I thought that I can just imagine an «ideal» API: something simple, designed exactly for my goal. What do I need? I need listing files, uploading and downloading. OK, I also would need deleting, updating modification date and creating directories. And... that’s it. And, as that’s an API, I don’t care how it’s implemented. I care that backend does these operations, no matter what it does in order to do these. (Even though it’s me who will be writing these backends.)

I still would study Google Drive and OneDrive APIs, and may be I’ll get some free time in order to write prototypes for those too. But for now I’ve designed two simple sketches I’ve shown to my mentor, Peter Bozsó (uruk-hai), and Eugene Sandulenko (sev).

First one is quite similar to what I’m using in my prototype:

file {
    path
    name
    size
    timestamp
    is_directory
}

service {
    file[] list_directory(path)
    bool upload(path, file_contents)    //may be "save"
    file_contents download(path)        //may be "read"
    bool delete(path)
    bool sync(service)
    bool create_directory(path) 
    bool touch(path)                    //update modification date
    service_info info()                 //username, available disk space, etc
    bool is_syncing()
}

In this one file is a struct with a few important fields. What I need is path, size, timestamp and a flag to know whether this file is a directory. No service-specific file id and stuff. All the operations are declared in service and different backends implement those, using this common file struct.

The other is a little bit more object-oriented:

file {
    path
    name
    size
    timestamp
    is_directory
    service

    file[] list()
    file_contents get_contents()
    bool set_contents(file_contents)
    bool delete()
    bool touch()            //update modification date
    bool sync(file)
}

service {
    file get_root_directory()
    file get_saves_directory()
    bool create_directory(path) 
    service_info info()     //username, available disk space, etc
    bool is_syncing()
}

There file has a reference to the service it belongs to and includes all file-related operations. That means I would have to implement file backends as well.

The thing is I’m fine with both of these approaches, and mentors opinions were divided. So, they advised me to write this post and get some feedback about it.

By the way, I also have an idea of making a backend for local filesystem as well. There is an AbstractFS in ScummVM, but I think it would be better to use one small Wrapper over it in order to work with local files in terms of the same API I’m working with remote ones.