At Appwrite, we strive to make software development for fellow Appwriters not only easy but also fun and beautiful. We want the experience of using Appwrite to be as pleasant as possible. Introducing custom ID support was another step towards that. So what are custom IDs?
π Overview
Appwrite is open source backend-as-a-service that abstracts all the complexity involved in building a modern application by providing you with a set of REST and realtime APIs for your core backend needs. Appwrite handles user authentication and authorization, databases, file storage, cloud functions, webhooks and much more! If there is anything missing, you can extend Appwrite using your favourite backend language.
Appwrite has various resources like documents, collections, files, users, teams, functions, and more, all identified by ( you guessed it) IDs! Until now, these IDs were automatically generated. While it made a lot of sense for them to behave this way, it presented some difficulty for developers migrating from a development to a production environment having to manipulate their IDs. Custom IDs give control back to developers allowing them to either use their own or choose auto-generated ones. Developers using Appwrite will now be able to assign a meaningful ID to their collections, functions, and more.
Custom ID support was one of the highly requested features by our community and was only possible with the recent Appwrite v0.12. Acting upon the feedback from our incredible community, with the new Appwrite version, we've introduced support for custom IDs for various resources provided by Appwrite. Now let's dive into how we have implemented custom IDs and how we still support the previous auto-generated IDs.
π Custom ID Implementation
Previously, all of the create
endpoints in Appwrite automatically generated 13 character long unique IDs for new resources. However, with support for custom IDs, we also wanted to allow developers to easily choose an auto-generated ID, if they wanted to. We added a new resource ID
parameter to all create endpoints of the resources that accept custom IDs. The ID can be at most 36 characters in length. It can be any valid alphanumeric value containing underscore, period, or hyphen, however, it cannot start with a special char. Finally, to allow developers to choose auto-generated IDs, we added a unique()
keyword, upon passing which, Appwrite will automatically generate the ID like before.
We have also made one tiny modification to auto-generated IDs. Previously there was a slight chance of ID duplication if they were created within the same microsecond and on the same host. We decided to prefix the auto-generated IDs with a 7-char random string to give them more entropy and prevent duplication. The new auto-generated IDs are now 20 characters in length with this version. We now understand how custom IDs are implemented and validated, next let's look at which resources in Appwrite support custom IDs.
π€ Do all resources support custom IDs?
Appwrite has many resources but not all of them support the new custom ID API. We had a lot of debates on which resources need to support custom IDs and we concluded that it only made sense to support custom IDs on resources that the developer would interact with directly. These include
- Project
- User
- Collection
- Document
- Function
- File
- Team
π€¨ How would it help me?
The first and foremost benefit of having custom ID support is allowing developers to assign meaningful IDs to resources. For example, to create a collection of books we can now give it an id of books
and access the documents in the collection using the assigned ID. With this, adding new books to the collection using the API looks more elegant, and as a developer, you will not have to keep track of a random string to refer to your books
collection.
Let's see how the code for listing documents look before and after the custom ID support.
- Listing documents in web before custom ID support
const sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('5df5acd0d48c2') // Your project ID
;
let promise = sdk.database.listDocuments('5df5acd0d48c2');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});
- Listing documents in web with custom ID support
const sdk = new Appwrite();
sdk
.setEndpoint('https://[HOSTNAME_OR_IP]/v1') // Your API Endpoint
.setProject('my-project') // Your project ID
;
let promise = sdk.database.listDocuments('books');
promise.then(function (response) {
console.log(response); // Success
}, function (error) {
console.log(error); // Failure
});
The code is much more readable with custom IDs. We know exactly which project and collection we are trying to access.
Secondly, if you were to setup two different Appwrite projects for your development and production environments, you had to keep track of the project IDs, collection IDs, function IDs and more in order to access those resources. You would need to create a separate config based on mode - development or production. Although it's not too difficult to create different configs per environment, with custom IDs that's one less thing to worry about. The project ID, collection ID and function ID can all be the same across development and production environments. Only the endpoints may be different.
Last but not least, while using REST API directly to access resources, endpoints look more elegant. For example, we are trying to get a list of documents for a Books collection that we have created. Previously with auto-generated ID, the endpoint would look like the following.
https://localhost/v1/database/collections/eead3asadf3e1/documents
By looking at the endpoint, it's not clear which collection we are trying to access and what documents might be. The same endpoint with custom IDs set for collection as books
will look like the following.
https://localhost/v1/database/collections/books/documents
Anyone looking at the URL can now easily understand that we are trying to access documents of the books
collection. These are the benefits of having custom ID support. It will make working with Appwrite much more straightforward and elegant. Next, we will look at the breaking changes we introduced to support custom IDs.
βοΈ Creating Resources after custom ID Support
All the creation endpoint of the resources that support custom ID now has a new required parameter resourceId
. For example, endpoint to create file, requires fileId
, and the method to create file in Storage service on all SDKs now requires fileId
. These parameters can be a custom IDs or a unique()
keyword if we want ID to be auto-generated like before. Keep in mind that the id
parameter is required.
Example: Creating a Collection
Creating a collection now requires an additional collectionId
parameter. For example, the new call to create a collection would look like the following.
NodeJS SDK
const sdk = require('node-appwrite');
// initialize client
let database = new sdk.Database(client);
database.createCollection('authors', 'Authors', 'collection', ['role:all'], ['role:member']).then(function(response) {
console.log(response);
}, function(error) {
console.error(error);
});
Dart SDK
import 'package:dart_appwrite/dart_appwrite.dart';
void main() async {
// initialize client
final database = Database(client);
try {
final collection = await database.createCollection(
collectionId: 'authors',
permission: 'collection',
name: 'Authors',
read: ['role:all'],
write: ['role:member']
);
print(collection.toMap());
} on AppwriteException catch(e) {
print(e.message);
}
}
This will create an Authors collection with authors
as the collection ID with collection
level read and write permission, role:all
and role:member
respectively. Learn more about this and other functions of database service by visiting our docs.
If you instead want to auto generate the ID for the collection, you can simply change the database.createCollection
to the following.
NodeJS SDK
database.createCollection('unique()', 'Authors', 'collection', ['role:all'], ['role:member']).then(function(response) {
console.log(response);
}, function(error) {
console.error(error);
});
Dart SDK
final collection = await database.createCollection(
collectionId: 'unique()',
name: 'Authors',
permission: 'collection',
read: ['role:all'],
write: ['role:member']
);
π€ Backward Compatibility
In order to keep things smoother for everyone, we try to keep breaking changes to the minimum. However, sometimes breaking changes are necessary. Even then, we try to make it backward compatible to smoother migration as much as possible. With the introduction to custom ID support, we have also introduced request filters to make it backward compatible. With request filters, we capture every request before reaching the endpoint handler and automatically add the default unique()
value to id parameters to support automatic generation like before. For example, when you make a request to create a user from an old SDK, our request filter will see that the request is missing the userId
parameter and adds userId=unique()
and forwards the request to the create user endpoint. This way, the handler gets all the required parameters and works as intended. You need to add the x-appwrite-response-format
header to the request to enable this logic. This is done automatically by SDKs.
π Conclusion
Custom IDs can be a very beneficial feature when used wisely. It will make accessing APIs more elegant and understandable. It allows us to give meaningful names to various resources and access them easily from your client applications. If you'd like to learn more about Appwrite you can visit the official docs. You can also check out our latest release in the release announcement. If you're stuck or need help with Appwrite, you can always join our Discord community of awesome Appwriters.
π Learn more
You can use following resources to learn more and get help regarding Appwrite and it's services
- π Appwrite Github
- π Appwrite Docs
- π¬ Discord Community
Top comments (1)
I cant wait to see Appwrite Cloud!!! I love this project