We are thrilled with the announcement of Appwrite 1.0. The new Appwrite release is our first ever stable version, and one of the biggest milestones for the project and the Appwrite community.
Appwrite 1.0 is not only about stability, like in every Appwrite release, the new Appwrite version is jammed with exciting new features that take Appwrite dev-experience to a new level. In this post, we have summarized everything you should know about the new release with links and resources for helping you to master all the cool new things version 1.0 has to offer.
Permissions 2.0
We have completely upgraded the Appwrite permissions mechanism, adding new capabilities, and more flexibility. Starting with version 1.0, we have introduced the permissions methods create()
, update()
and delete()
to allow granular control over which end user has access to which resource.
The new create()
method will allow you to have more control over who can create a document or a file in a database collection or a storage bucket. For convenience, we have also kept the write()
permissions which will be used as an alias for create()
+ update()
+ delete()
.
From now own you will also be able to use the role any()
to give both signed or guests users access to read or write. This is now possible since the introduction of buckets. By default Appwrite will still keep your resources safe from unauthorized access, but now you could explicitly allow any kind of user to create resources to be stored on your Appwrite backend.
For more convenience, we have upgraded all SDKs to support both the new Permission
and Role
classes for quick and easy completion of the different permissions method and allowed roles.
import { Client, Databases, Permission, Role } from "appwrite";
const client = new Client();
client
.setEndpoint('https://[HOSTNAME_OR_IP]/v1')
.setProject('[PROJECT_ID]');
const databases = new Databases(client, '[DATABASE_ID]');
let promise = databases.createDocument(
'[COLLECTION_ID]', // Collection ID
{'actorName': 'Chris Evans', 'height': 183}, // Data
[ // Permissions
Permission.read(Role.any()), // Anyone can view this document
Permission.edit([Role.team("writers"), Role.team("admin")]), // Only writers and admins can edit this document
Permission.delete([Role.user("5c1f88b42259e"), Role.team("admin")]) // Only user 5c1f88b42259e and admins can delete this document
]
);
promise.then(function (response) {
console.log(response);
}, function (error) {
console.log(error);
});
Queries 2.0
The Queries system has also seen a major overhaul in Appwrite 1.0. We notice the list endpoints in Appwrite had inconsistent, yet bloated function signatures. For example, consider the example below which does nothing but sort by title
in ascending order:
import { Databases} from "appwrite";
const databases = new Databases(client, "[DATABASE_ID]"); // 'client' comes from setup
databases.listDocuments(
'movies', // collectionId
[], // queries
25, // limit
0, // offset
'', // cursor
'after', // cursorDirection
['title'], // orderAttributes
['ASC'] // orderTypes
);
There are far too many parameters in the listDocument()
method. To solve this problem we’ve overhauled the Queries system so that list endpoints take only a queries
parameter. Each type of query, sort, or pagination action will now be passed to list endpoints through the queries parameter.
Here’s the same example in Appwrite 1.0:
import { Databases, Query } from "appwrite";
const databases = new Databases(client, "[DATABASE_ID]");
databases.listDocuments(
'movies', // collectionId
[
Query.orderAsc('title'), // Order results in ascending order by title
], // queries
);
This new syntax is much more concise and easy to write. The new query also does pagination in a similar fashion like before:
import { Databases, Query } from "appwrite";
const databases = new Databases(client, "[DATABASE_ID]"); // 'client' comes from setup
// Page 1
const page1 = await databases.listDocuments('movies', [
Query.greaterThan(year, 1999),
Query.limit(25)
]);
const lastId = results.documents[results.documents.length - 1].$id;
// Page 2
const page2 = await databases.listDocuments('movies', [
Query.greaterThan(year, 1999),
Query.limit(25),
Query.cursorAfter(lastId)
]);
Appwrite also required an exact index for querying and sorting in previous versions. If you had a query like the one below, you would have needed an index with the exact attributes and order of [‘title’, ‘year’, ‘studio’]
. The index of [ ‘year’, ‘title’, ‘studio’]
or [‘title’, ‘year’, ‘studio’, ‘language’]
would not have worked.
// Page 1
const page1 = await databases.listDocuments('movies', [
Query.equal(‘title’, “Lion King”),
Query.greaterThan(‘year’, 1999),
Query.equal(‘studio’, ‘Disney’)
]);
With the new flexible indexes in Appwrite 1.0, you can now perform the query with either of the previously mentioned index examples. This is the first of a series of planned improvements to increase database flexibility in Appwrite in the coming weeks and months.
DateTime Attributes and ISO8601 Support
A new attribute was introduced in Appwrite 1.0 after popular demand, which is DateTime Attributes. The new DateTime attribute follows ISO 8601 and displays time information in a human readable string. All DateTimes will be stored in UTC to avoid timezone confusion.
This is better than Unix Timestamps in the sense that it can represent dates before 1970 and after 2038. This is useful for scheduling or birthday type information that often require longer time frames. To be consistent, all timestamps returned by different Appwrite endpoints are also in DateTime format and UTC timezone in Appwrite 1.0.
Password Hashing
Appwrite 1.0 introduces a new API that allows you to import password hashes in different formats. The supported formats are BCrypt, MD5, SCrypt, SCrypt Modified (Firebase), Argon2, PHPass, SHA, and Plain Text. Appwrite will also be using Aragon2 as the new default hashing algorithm as recommended by OWASP. Here’s an example importing a password using BCrypt:
import { Client, Users, ID } from 'appwrite';
// make sure to have client with endpoint and project ID
const users = new Users(client);
const passwordHash = '$2a$12$SnuhggUBPwc0ZTFsLeENVuKD.UcNOl6h/fIFkzih8pRQYZa2oNVM2'; // Hash of password: AppwriteIsAwe$ome
users.createBcryptUser(ID.unique(), 'test@appwrite.io', passwordHash);
This is hashing API is only available on Server SDKs and intended for importing existing users from other platforms. All imported hashes that are imported are converted to Argon2 after the user is created, like normal users created on Appwrite.
Zstd Compression
In previous versions of Appwrite, we’ve only supported file compression using Gzip. In Appwrite 1.0, we introduced file compression using Zstandard which is a fast compression algorithm with high compression ratio intended for all types of online storage. You can now choose to use this type of compression algorithm in the Appwrite Storage service.
What is Coming Next?
Appwrite still has lots of room to grow and evolve. We're excited for the future roadmap of Appwrite and confident in the potential of Appwrite to revolutionize how software is built and maintained. Together with the open-source community and wider developers community, we believe Appwrite has endless possibilities to simplify developers' lives and allow all of us to focus on innovation.
Get Involved!
Appwrite is built and designed by a community of passionate open-source developers. Getting started in the Appwrite community and becoming more involved is very easy. While many love to support the project with code contributions, there are other great ways to give a hand. Helping in the Discord community or through GitHub issues, sharing your feedback, reporting bugs, or spreading the word by creating written or video content and engaging with other developers on social media. Every contribution counts and helps us make Appwrite better.
Top comments (2)
Congrats for the stable release! Gpad for new permissions. Long due
Thank you! Some more cool features are in plan for the database, more news soon!