- Implementation Owner: @eldadfux
- Start Date: 16-12-2020
- Target Date: 20-12-2020
- Appwrite Issue: None
Add a the option to enable different response filters to the Appwrite response object. This filters will act as a middleware and allow us to manipulate the response code before sending it to the HTTP client.
What problem are you trying to solve?
While in beta we are changing some of our APIs response formats.
What is the context or background in which this problem exists?
Appwrite is still in beta, and as we progress with the project development, we need to break some existing APIs response format from time to time. Initially, this wasn't an issue because the product is still in beta, but it has become a requirement with growing usage by the developers' community.
Once the proposal is implemented, how will the system change?
A new API option will allow devs to keep backward compatibility.
We should introduce a new env variable and HTTP header that will allow to change the response format. This variable & header will allow devs to enable a response object filter which will parse the Appwrite response to continue support for old Appwrite response formats without breaking or changing our developers apps when upgrading an appwrite version.
Should be checked on server startup. If the value is not empty we should init the relevant filter. If not filter is avaliable we should throw an error using the Console::error method and stop the proccess with exit(1);. Make sure to add the new var to Appwrite docs page: https://appwrite.io/docs/environment-variables#system-settings
Should be checked on each request (general.php / ->init() can be a good location). If the value is not empty we should init the relevant filter. If not filter is avaliable we should throw an 404 HTTP error with relevant error message.
Added 2 new method to Appwrite response class (src/Appwrite/Utopia/Response.php) called static function setFilter(Filter $filter): self
and static function getFilter(): Filter
. The new method will set and get the new filter to a static property called self::$filter
. Add a method called static function isFilter(): bool
to check if a filter has been set or is null.
Create a new Appwrite\Utopia\Response\Filter class (src/Appwrite/Utopia/Response/Filter.php). The interface should decalre an implemntation for the parse(array $content): array
method. Each new filter will implement the interface and use the parse method to manipulate incoming data. Create our first filter (Appwrite\Utopia\Response\Filters\V06) to accept current version (v0.7) data and convert it to v0.6 data. For that we'll need to run both instances of Appwrite to manually convert data structures.
Add a piece of code in the response output stage, that will check if a filter is set and will execute his parse
method and alter the response output before it is returned to the client. A good location for this method to run might be: https://github.com/appwrite/appwrite/blob/0.7.x/src/Appwrite/Utopia/Response.php#L296
/v1/locale/countries?project=console
{
"AF": "Afghanistan",
"AL": "Albania",
"DZ": "Algeria",
"AD": "Andorra",
"AO": "Angola",
"AG": "Antigua and Barbuda",
"AR": "Argentina",
"AM": "Armenia",
"AU": "Australia",
"AT": "Austria",
...
{
"sum": 194,
"countries": [
{
"name": "Afghanistan",
"code": "AF"
},
{
"name": "Albania",
"code": "AL"
},
...
/v1/teams?project=console
{
"sum": 25,
"teams": [
{
"$id": "5e5ea5d40c1b1",
"name": "New Project",
"dateCreated": 1583261140,
"sum": 1
},
{
"$id": "5e6081aca576c",
"name": "Project Y",
"dateCreated": 1583382956,
"sum": 1
},
...
{
"sum": 1,
"teams": [{
"$id": "5fdca0529143a",
"$collection": "teams",
"$permissions": {
"read": ["team:{self}"],
"write": ["team:{self}\/owner"]
},
"name": "Project 1",
"sum": 1,
"dateCreated": 1608294482
}
...
In case the parse method is missing some data to properly construct the response, just use a reasonable default value of the same type and structure.
Add unit-tests for the new methods in the Response class, and for our first filter using mock data as input.
In the future we might want to do something similar to the Request input in case we'll introduce any API signature breaking changes.
None.