Luracast / Restler

Simple and effective multi-format Web API Server to host your PHP API as Pragmatic REST and/or RESTful API
http://luracast.com/products/restler/
GNU Lesser General Public License v2.1
1.36k stars 317 forks source link

Restler 3.0 Feature Requests and Ideas #22

Closed electrical closed 11 years ago

electrical commented 12 years ago

Since you asked for idea's, let me start with some :-)

  1. Output structure: http://groups.google.com/group/api-craft/browse_thread/thread/9b046e863b5943df. Metadata is something that can be generated from the API it self. Links can be generated from the class the user builds.
  2. Correct header settings: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html. Think some things here can be found that are useful. Like: 14.7 Allow
  3. Pagination: limiting the returning result set. Can be build in the api class of the user self, but perhaps some core functionality can be build in the API core ?
  4. JsonP: JsonP as part of the package; JsonP becomes more and more important with cross-domain usages.
  5. Versioning Support: To have an inbuilt Restler way to manage your API versions (Request from @KitCarrau in issue #21)

More will follow when they pop up in my mind :-)

Luracast commented 12 years ago

Just caught up with some development work, will update soon :)

Luracast commented 12 years ago

To followup on #26 allowing file uploads in Restler. Restler 3 is going to restrict mime types that is not supported by the enabled format classes for security reasons. This means we need to add a format class to enable support when we need it. I created the following class for that purpose

<?php
class UploadFormat implements iFormat
{
    /**
     * use it if you need to restrict uploads based on file type
     * setting it as an empty array allows all file types
     * default is to alow only png and jpeg images
     * @var array
     */
    public static $allowedMimeTypes = array('image/jpeg', 'image/png');
    /**
     * use it to restrict uploads based on file size
     * set it to 0 to allow all sizes
     * please note that it upload restrictions in the server
     * takes precedence so it has to be lower than or equal to that
     * default value is 1MB (1024x1024)bytes
     * usual value for the server is 8388608
     * @var int
     */
    public static $maximumFileSize = 1048576;
    /**
     * Your own validation function for validating each uploaded file
     * it can return false or throw an exception for invalid file
     * use anonymous function / closture in PHP 5.3 and above
     * use function name in other cases
     * @var Function
     */                             
    public static $customValidationFunction;

    const MIME = 'multipart/form-data';
    const EXTENSION = 'post';
    public function getMIMEMap ()
    {
        return array(self::EXTENSION => self::MIME);
    }
    public function getMIME ()
    {
        return self::MIME;
    }
    public function getExtension ()
    {
        return self::EXTENSION;
    }
    public function setMIME ($mime)
    {
        //do nothing
    }
    public function setExtension ($extension)
    {
        //do nothing
    }
    public function encode ($data, $humanReadable = FALSE)
    {
        throw new RestException(405, 'UploadFormat is read only');
    }
    public function decode ($data)
    {
        $doMimeCheck = ! empty(self::$allowedMimeTypes);
        $doSizeCheck = self::$maximumFileSize ? TRUE : FALSE;
        //validate
        foreach ($_FILES as $index => $file) {
            if ($file['error']) {
                //server is throwing an error
                //assume that the error is due to maximum size limit
                throw new RestException(413, "Uploaded file ({$file['name']}) is too big.");
            }
            if ($doMimeCheck && ! in_array($file['type'], 
            self::$allowedMimeTypes)) {
                throw new RestException(403, "File type ({$file['type']}) is not supported.");
            }
            if ($doSizeCheck && $file['size'] > self::$maximumFileSize) {
                throw new RestException(413, "Uploaded file ({$file['name']}) is too big.");
            }
            if(self::$customValidationFunction) { 
                if(!call_user_func(self::$customValidationFunction, $file)){
                    throw new RestException(403, "File ({$file['name']}) is not supported.");
                }
            }
        }
        //sort file order if needed;
        return $_FILES + $_POST;
    }
    public function __toString ()
    {
        return $this->getExtension();
    }
}

Hope it is self explanatory, ask me if you need help understanding

electrical commented 12 years ago

@Luracast Will it work with doing a POST and PUT http verbs? Because at the moment as far as i understand it it's a separate format ? ( or i'm just to tired :p )

Luracast commented 12 years ago

@electrical I dont think it will work with PUT. It is not a common use case anyway :)

electrical commented 12 years ago

@Luracast Well that depends, for like updating a profile picture or something ? :-)

Luracast commented 12 years ago

@electrical PUT is not directly supported in PHP. for post it automatically parses request and creates $_POST, but for PUT, I have to manually do the parsing in Restler, it will be the same for Upload as well.

I will look in to it again in the near future :)

electrical commented 12 years ago

@Luracast Cool! For sorting responses;

http://groups.google.com/group/api-craft/browse_thread/thread/12d8fffa17f89f69

The idea's is to do the following:

?sort=field(ASC),field2(DESC)

is that implementable for you?

Luracast commented 12 years ago

@electrical currently it can be handled manually by the API methods. It will make more sense to implement it in Restler when we add this along with a db layer

electrical commented 12 years ago

@Luracast Not sure if a DB layer should be implemented, many people have their own classes for that ( i know i do :p ) Would be nice to pass the sort stuff as an array to the functions or something. but that's just my idea :-)

electrical commented 12 years ago

@Luracast Found this regarding PUT upload support in php: http://php.net/manual/en/features.file-upload.put-method.php

roynasser commented 12 years ago

I'm going to vote strongly against a db layer too... :/

One of the good things of restler is that it doesnt have a db layer, so it is easy to implement into existing project, with existing dbs, etc... for an api layer that is extremely important. adding a db layer would not only distract time from (imho) more important things in terms of coding, it would also bloat the code for the ppl who use their own db layers, and from ppl who use restler as the API part of existing system... i think a db layer is a real bad idea personally.... please lets not mix things.... i see a bunch of great frameworks which would be great were they not tied to their own db layers - id hate to see that with restler...

Luracast commented 12 years ago

Do we need a DB layer for Restler?

@electrical & @RVN-BR I hear you and understand your concerns :)

Restler is never tied to a single thing, be it a format or authentication class. Any one can can create their own class and plug it in to the system, no inheritance needed, just following few simple rules (implementing the right interface class) will do.

All the format classes, and Authentication classes that comes with Restler are purely implementation examples.

I think the DB layer should also be (if at all) created in a similar way, with a simple interface and as a implementation example. And it should remain as a piece that you choose to add or leave( not part of the code, except the interface definition which will be part of the code)

Let me know what you guys think!

electrical commented 12 years ago

I think there are to many different ways to do db stuff that it's hard to make an implementation for it in Restler. I really think it's something that shouldn't be implemented ( right now atleast )

rpip commented 12 years ago

No! No! No! Restler does not need a DB layer. There are plenty ORMs out there and people are freee to use of any of them. Choice. That"s the keyword. Besides, what makes Restler unique and my preferred REST lib is it"s ability to comfortably sit on top of an existing project, and still give you all the space u need to develop the app.

roynasser commented 12 years ago

Personally I spent the last 6mos+ trying to find a DB layer that could work within my existing projects, for multiple developers, and not require a radical redesign of code or structure in order to see any benefit... I was unsuccessful...

For me, quicker, more manageable SQL is more valuable than slower less optimized, quicker to write pseudo code (afterall its code-once, execute millions of times)....

I little while ago I cam across this blog http://leftnode.com/entry/the-last-php-pdo-library-you-will-ever-need and completely gave up my search (after being satisfied I wasnt crazy to go orm-less)... I currently run my own "db layer"... it supports fallback, prepared statements, and a bunch of other things that are useful to my code, including db cache (which isnt a simple "on-off" setting, because cache needs to be applied only to cacheable data, etc)...

thats why I make the case that a db layer will not really benefit restler in its main function...

electrical commented 12 years ago

@RVN-BR Just wondering; would you mind to share that ? or would you like to keep it to your self? Im still searching for a better mysql layer :-)

roynasser commented 12 years ago

No problem... maybe best to do it by e-mail though, unless someone else is interested (id rather do it by email as the code isnt fully commented, if at all, and parts of it are in english and parts arent esp my validator - see below... it is quite simple though)? I also built an input validator of sorts function to use coupled with restler... (the db layer is heavily based on the one I linked to, though...)

Basically what I can do is send the request_data array through my function, and set its options to validate the input. I can say what each input should be (type, validation, and default value if its empty)... with that I'm safe to send the treated array straight into my prepared statement.

It was built to suit my need basically, but its pretty generic...

There is a class called pdb if i'm not mistaken that is similar but it has some protection for that nasty "server has gone away" errors that pdo has... I'm going to try and port the fix over sometime... (link: http://code.google.com/p/digg/wiki/PDB )

electrical commented 12 years ago

My email address is richard@ispavailability.com Thank you :-)

Luracast commented 12 years ago

Guys,

I always wanted to ask you this. I'm interested in knowing how you use Restler, and build things around it. Which will give me insights and allow me to improve Restler using the collective knowledge

Recently few of you started sharing the the support classes built for Restler and I appreciate it a lot. I welcome every one to do so in following ways

  1. Create them as reusable examples and share it with the whole Restler community
  2. If you dont have time, just pass me the project removing just sensitive data, I will build examples to share
  3. Share the source just with me, so I get the insights which will be used to improve future versions of Restler

Just do which ever you are comfortable with

You can reach me by email. Lets work together for the greater good

I promise that Restler will always remain free and open source

roynasser commented 12 years ago

Hi Luracast,

I'll send you some of my stuff soon... its really way too messy right now... I sent electrical some db stuff last night and after i added some comments to it I was so ashamed of the messy state I almost didnt sent it off to him :o anyways, the code itself is working and is surprisingly useful and quick in most benchmarks. Some things still need to be reworked and "unlayered" for efficiency but in the end I'll send you a couple of examples.

Luracast commented 12 years ago

@RVN-BR Cool! looking forward to it :)

electrical commented 12 years ago

I also will try to share some stuff. Most of it is extremely simple though and not that special.

@RVN-BR how do you do benchmarking? Im wondering to the memory usage and response times.

electrical commented 12 years ago

@Luracast Just wondering how far you are with the new version for testing ;-)

Luracast commented 12 years ago

Pending things for Restler 3.0 release

Moved to the Wiki documentation for easy access

electrical commented 12 years ago

I've been going over your list and find a few things i would like to discuss :-)

Logging support: Should be in one of the manager classes. Don't think it should be a core feature.

iFilter interface for creating custom filters (countryFilter, ipFilter etc): What do you mean with this? ( sounds like a filter which could be a manager class )

Validating parameters and iValidate interface: Allot of people have their own validation functions, aint that gonna cause issues. and also, should that be a core feature?? Or could be a manager class?

Caching support: simply setting the correct headers i think? Or are you planning other caching stuff?

Cheers.

roynasser commented 12 years ago

I have my own logging/db/audit/filter-validate classes that I ported over from other projects...

If they are easily implementable it would be ok, but otherwise I'd keep them just as plugin options for people starting from scratch on restler... as I've said before, the great power I see in restler is that we dont need to start from scratch to be able to use it like in some other frameworks...

my classes are kind of tied in together in some points (for example, authentication will log failures using my log class... the log class writes to the DB using my db class, and the db class writes audit data for tables using the audit functions in the log class) so its kind of inter-twined...

Anyways, I will release some parts which may be useful to others, sorry I havent so far...I'm currently away from the office for holiday, I'll be back next week, hopefully i may have time...

PS: I instantiate basically 2 objects today, one for the DB layer and one for my "application object". the app object has all of the data validation, etc, as well as some more info from authenticated users... The only draw back is that I need to add a "Global $DB, $App;" line on the top of every function... Maybe it would be a better way if somehow I called them from within the restler $this-> object? I suppose the change wouldnt be that great ( a global replace from $DB to $this->DB for example?) would this make for better memory/eecution time?

electrical commented 12 years ago

@RVN-BR I have a very nice mainframe class so you don't need the Global stuff. You can do things like:

$db = mainframe::init("database");

I made it open source: https://bitbucket.org/electric/php_classes_mainframe/overview Will need to update it though because it's an older version ( made some nice modifications to it )

I got it together with my autoloader class so the memory footprint will always be as small as possible because classes that i don't need will not be loaded :-)

roynasser commented 12 years ago

Electrical, sorry, i dont quite understnad... you mean I'd need to do a call to init the DB at each function? instead of a global, a $db = mainframe::init(database)?

but then i'd need to do checks to see if its already connected by a previous function, etc, right?

I'm not really understanding the advantage to this method? it still requires a call (not a global, but a mainframe::init) at every function... so what is the gain (if any)? or any other advantages i'm just not grasping?

thanks for sharing!

electrical commented 12 years ago

seems i wrote it to fast in my night shift ( i've just come home now so i'll try to take bit more time for it )

The mainframe class basically manages all instances of your classes that you initialize. That way you don't need the Global $db in the functions but you can use the $db = mainframe::init("database"); call.

yes, you will need to call it in every class but you can for example do something in the construct function like: $this->db = mainframe::init("database");

I've created it to avoid using the Global part simply because it's ugly. And together with my autoloader ( also available on bitbucket; which i also need to update btw ) it manages all my classes and the loading of them.

I hope this makes it a bit clearer :-) if not, let me know and i'll try to create an example.

Cheers.

roynasser commented 12 years ago

Hi Richard, yes it is clear now! But, without meaning to be picky, what is the benefit instead of say instantiating my DB class in the constructor like such $this->db = new MyDBClass?

And does your mainframe::init take any class to initialize, or only specific ones made for it? (i.e. could I use it with my existing classes? what modifications would be necessary?, and what is the difference from a regular instatiation ($a = new DBClass)?)

thanks for clearing it up! it sounds interesting but I'm not really understanding its purpose if its just an instantiation "wrapper" or if it does more than that...

electrical commented 12 years ago

Good arguments, seems i've haven't been complete yet. The biggest benifit ( imho ) is that for example you can initialize it somewhere ( for example in the index file of the API:


$db = mainframe::init("database");
$db->AddHost("............"):

And then somewhere else you can call it again


$db = mainframe::init("database");
$db->DoQuery("......");

So it will keep the object as it was set in the index file with all the settings. Does it make more sense now?

electrical commented 12 years ago

@Luracast Did your read up about the PATCH support ?? seems to a standard now. think it will imply some changes.

Luracast commented 12 years ago

@electrical Yes, We will have PATCH support in Restler 3 :)

roynasser commented 12 years ago

@electrical, I understand now the mainframe... basically it is keeping all of the instantiated objects in the mainframe class itself, and then you can create a hook instead of calling a global.

Looks nice... You mentioned you have a new version? mind uploading that? I'd like to take a closer look.

thanks!

electrical commented 12 years ago

@RVN-BR Correct :-) I'll need to find it and add some doc to it and already thinking of an extra function. Give me a couple days and i'll put it online.

electrical commented 12 years ago

@RVN-BR here it is: https://github.com/electrical/php-mainframe

Edit: im publishing more of my classes onto github. might be something interesting in there :-)

roynasser commented 12 years ago

Thanks @electrical ! I'll use that... :)

I'm also looking for a better way of doing autoloading... I need to structure my files a bit better... We have different developer teams which will have different access levels in our code storage (whatever it is, be it git,svn, whatever), so I need to be able to include things quickly (i.e. not "crawling" directories at every web request - at least not in production), and something which allows files to be included from different places in the directory tree.

Any suggestions?

One basic idea could be something like this:

API/Level1/ API/Level2/ API/Level3/

So developers would have access to these directories based on their privileges, Level1 would see all 3, Level2 would see 2 and 3, and Level3 only 3...

Inside each of the "Level" directories, I can then have a constant structure, something like say:

Lib/ - contains library classes ModuleClasses/ - restler functionality classes

Now this would be quite complex, and it would also mean that each developer needs a good documentation in order to know what they are developing for... A "loader" class would iterate through the Level1, Level2, Level3 directories adding any files that are included through it. The advantage of this is that a programmer can extend a class without having access to it... basically if you add Level3/ModuleClasses/test.php, it will be loaded after Level1/ModuleClasses/test.php which means that it could just extend the test class with other functions...

This is good but I can see some complexity... overall I dont know if this is the best way to go since several developers will be writing the API, but not all of them will have access to all of the code... any ideas?

Luracast commented 12 years ago

Versioning in Restler 3

Usage Example

<?php //index.php (gateway)
spl_autoload_register('spl_autoload');

$r = new Restler();
//set the version first before loading API classes
$r->setApiClassPath('services');
$r->setAPIVersion(2);
$r->addAPIClass('Math');
$r->addAPIClass('Hello');
$r->handle();

here is how the files are located

examples/
+-- versioning/
+-- index.php
    +-- services/
        +-- math__v2.php
        +-- v1/
            +-- hello.php

Here API Classes are named as Math & Hello. We support appending the version number with v__{version} in the file name or placing the file inside version folder v{version}

when the user is making a request for

GET /examples/versioning/v2/hello

Autoloader will attempt to locate version 2 of hello, failing on which it will load the next lower version.

So even though your api version is increased, you need not rewrite classes that does not require a change. Any missing version will be served with previos version automatically

Here is the code that makes this work

<?php
#======== From restler.php Restler class ==============
    protected $_apiVersion = 0;
    protected $_apiMinimumVersion = 0;
    protected $_apiClassPath = '';

    public function setApiClassPath($path){
        $this->_apiClassPath = ! empty($path) && 
        $path{0} == '/' ? $path : $_SERVER['DOCUMENT_ROOT'] .
        dirname($_SERVER['SCRIPT_NAME']) . '/' . $path;
        $this->_apiClassPath = rtrim($this->_apiClassPath, '/');
    }

    public function setAPIVersion ($version, $minimum=0, $apiClassPath='')
    {
        if(!is_int($version))throw new InvalidArgumentException
        (
            'version should be an integer'
        );
        $this->_apiVersion = $version;
        if(is_int($minimum))$this->_apiMinimumVersion=$minimum;
        if(!empty($apiClassPath))$this->setAPIClassPath($apiClassPath);
        spl_autoload_register(array($this, 'versionedAPIAutoLoader'));
    }

    public function versionedAPIAutoLoader ($className)
    {
        $path = $this->_apiClassPath;
        $className = strtolower($className);
        $apiVersion = $this->_apiVersion;
        while ($apiVersion) {
            $file = "{$path}/v{$apiVersion}/{$className}.php";
            if (file_exists($file)) {
                require_once ($file);
                return TRUE;
            }
            $file = "{$path}/{$className}__v{$apiVersion}.php";
            if (file_exists($file)) {
                require_once ($file);
                return TRUE;
            }
            $apiVersion --;
        }        
        $file = "{$path}/{$className}.php";
        if (file_exists($file)) { 
            require_once ($file);
            return TRUE;
        }
        return FALSE;
    }

@RVN-BR above code may serve as an example for solving your problem :)

roynasser commented 12 years ago

This is very nice, and it also provides so that you dont need to copy the entire previous tree in order to change just a couple of files...

Nonetheless, how does your index.php file keep track of different versions? I assume you will have different index,php for different versions? If not, how do you add or remove classes in different versions?

Your code seems very helpful in solving my proposed scenario, but any comment about it? any better way around it? Should I perhaps just go directory-per-directory to allow access for the developers, and not have a "hierarchy"? (i.e. give each developer access to the directory that holds the module they develop, instead of having it in a group hierarchy?)

any implications on api design of either choice?

Luracast commented 12 years ago

@RVN-BR all versions are served from same index.php setAPIVersion($version, $minimum) captures the current/latest version and minimum version supported by the system. when the request is made with out a version number, latest version will be served.

Regarding your scenario, have a look at #3

roynasser commented 12 years ago

Hey @Luracast , I see what you mean... nonetheless, it may be an issue if stopping support for a particular function after version X... Although not ideal these changes do happen, and that is why in my "workaround" I ended up with a specific routes file for each version... it may involve slightly more duplication, but it allows for adding and removal of functions on a per version basis (a large part of what versioning is about, from what i see)...

In your scheme, when I'm on version 3, I have addapiclass calls for items which exist only on version3, right? will it just ignore these if they arent in previous ones? I assume so? What about if it doesnt even exist in version 3 (probably typo), I assume it may just fail silently?

I'm still not seeing much benefit to eliminating the per-version "class list"... Explicitly being able to add or remove access to a specific functionality within a specific version may be something desireable, it is part of the flexibility of versioning afterall?

About the issue you pointed me to, that would be in terms of client security, this is all taken care of... i'm now addressing developer security. In large development teams in organizations we often have teams that dont see some core code, etc, therefore we must isolate their access in the Version Control/File system. any comments if anyone has implemented similar things?

roynasser commented 12 years ago

@Luracast one thing I would suggest adding to your autoloader is a possbility of recursion when searching for files to autoload?

Also I'd suggest a configurable file name convention, so we can specify a prefix or suffix for class files. for example: whenever you add the api Test, it would look for the file api.test.class.php (prefix = api, suffix = class)...

personally I've been using a prefix of class, without any suffix, but I suppose different people have different conventions so a prefix/suffix would be a good way?

indyjoe commented 12 years ago

Hello,

Firstly, thank you for a great framework. The work is very much appreciated. I have a couple questions in regards to this comment on file uploads above. https://github.com/Luracast/Restler/issues/22#issuecomment-3920871

How would I use the UploadFormat class in a crud action? Example...

function insert ($rec)
{
    $name = mysql_escape_string($rec['name']);
    $email = mysql_escape_string($rec['email']);
    $photo = mysql_escape_string($rec['photo']);
    $sql = "INSERT INTO authors (name, email, photo) VALUES ('$name', '$email', '$photo')";
    if (! $this->db->query($sql))
        return FALSE;
    return $this->get($this->db->lastInsertId());
}

Also, would I need to modify this line... $r->setSupportedFormats('JsonpFormat','JsonFormat', 'XmlFormat');?

Essentially, I am a bit lost on how to implement. Apologies if this is an inappropriate place for the questions.

Luracast commented 12 years ago

@indyjoe you are welcome to post related questions here :) sorry for my delayed reply!

For Restler 2.0 you do not need UploadFormat. Only for Restler 3.0 and above you need to add

<?php //index.php (gateway)
...
$r->setSupportedFormats('JsonpFormat','JsonFormat', 'XmlFormat', 'UploadFormat');
...

for Restler 2.0 your insert function can be (it will also work for Restler 3.0)

<?php

...
function post ($request_data) //make note of the function name and param name
{
    $name = mysql_escape_string($request_data['name']);
    $email = mysql_escape_string($request_data['email']);
    //for photo we only store the path for the image
    //you may want to move the file to different location
    $photo = mysql_escape_string($_FILES['photo']['tmp_name'].'/'.$_FILES['photo']['name']);
    $sql = "INSERT INTO authors (name, email, photo) VALUES ('$name', '$email', '$photo')";
    if (! $this->db->query($sql))
        return FALSE;
    return $this->db->lastInsertId();
}
...
Luracast commented 12 years ago

@RVN-BR I hear your points. If you want to remove support for a resource you may use getMaximumVersion() method which returns the maximum version number supported by that resource(class). We can create an interface called iVersionedAPI to impose this where needed.

You are right, a resource implemented on version 3 wont be available on version 2 and trying so will result in 404 error.

I believe, versioning this way has more merits. Lets hear others view as well.

regarding different naming conventions, we can allow users to tweak it using iRoute interface and also with the default implementation using naming templates as static properties.

electrical commented 12 years ago

Here are my thoughts about the versioning after having thought more about it. Versioning can be handled by the framework but there are a few side notes.

You will need to put at every class for which API version it counts. Minimal API version idea is not usable since the very first api functions will always work until you deprecate them in a newer version. So you would need to say per class what the maximum api version is. This will require some work for the coder but it's doable..

Versioning per function will be extremely hard if not impossible.

If one requests version 2 api all functions from the v1 api should work ( which are not limited by the max api version set to 1 ) and all the functions for version 2 api.

The main problem is then... how are we going to fit this all into the loading process.... including all the files by hand is going to be near to impossible so some kind of auto loading is needed.

for a directory structure it's hard to make anything generic because every application is different....

For example mine is like this:

/path/to/app/modules/{mod_name}/api/classes/{modname}{controller_name}.class.php

for me i can create a directory in the classes folder like v1 and v2 to split up the api version specific classes. But then the auto loader needs to check all the folders from the highest version down to version 1 to find the correct class. And then something will need to make it possible to enable the api classes in the correct way with the right prefixes and stuff.

My urls are going to be like this: api.hostname.com/{mod_name}/{controller_name}

But then again, for anyone else their situation can be, and most likely will, be different....

I strongly believe that if we want to fully automate the versioning process within the framework it will need to be as dynamic as possible. And i also believe that as long that isn't possible it should be possible to create your own sub directories for the different api versions with their own index file ( where all the routing is done and stuff )

I hope this will have some useful contribution to the versioning discussion :-)

roynasser commented 12 years ago

(Please dont take this post badly its just considering my own cases, and experience as well as my view on standards. In order to build a unique framework for many different apps my vision shouldnt be considered by itself, it is only one point of view...)

Personally I understand that version backward compatiblity is at the developers option that is why the consumer of the api has the choice of using a lower version, therefore, looking for older functions in an older directory version is unnecessary (if not entirely bad) in my opinion...

With that, each version can have its own routing file to make the above as easy and as painless and transparent as possible... a version change can be a major thing, so assuming a fallback is extremely dangerous and generalizing, which is why I think it shouldnt be done...

For autoloading I think that something flexible and customizable would be really great, so far I havent found it, i have something makeshift which caches file structure and looks recursively down (not up into another version)... it will also work with my customizable naming scheme...

Anyways, I'm anxious to see restler 3 although i admit i'm a bit afraid of how much i will have to re-write :p

but i'm really looking forward to it! :)

electrical commented 12 years ago

Hi @RVN-BR

I agree that backward compatibility makes it more difficult. My reasoning regarding looking into lower API version dir's is to avoid duplication of files. On the other hand you are right that its not the way to go; for example, what if you want to drop v1 because its getting to old ( not used anymore )

When you have in each version directory the whole API classes ( can have duplicates with the previous version ) the whole process does get allot easier :-) I think that is the way to go.

rpip commented 12 years ago

Looks like i have a lot to catch up with. My primary concern still remains that Restler is lean and does not dictate what ORM the developer uses or how best to deploy the app. Restler should just be as it is - sweet and simple.

roynasser commented 12 years ago

Hi @mawuli-ypa ! All that you say are main concerns for me too!!!

Nonetheless, when develpping for realy world use, all of the above issues have become real pressing... so while I also agree that I want restler to be lean and not dependent on an ORM, its important for either restler to implement an API Version system, or for me to implement it myself...

Since all of the features on restler are "optional" by design, its better to discuss them and try and make them as flexible and useful in a variety of scenarios as possible...and if we dont like it, hey.....its optional! (take authentication, its there, even on the current version, but you arent obliged to used it...)