## Extensions - Implementing Drivers Puter's concept of drivers has existed long before the extension system was refined, and to keep things moving forward it has become easier to develop Puter drivers in extensions than anywhere else in Puter's source. If you want to build a driver, an extension is the recommended way to do it. ### What are Puter drivers? Puter drivers are all called through the `/drivers/call` endpoint, so they can be thought of as being "above" the HTTP layer. When a method on a driver throws an error you will still receive a `200` HTTP status response because the the invocation - from the HTTP layer - was successful. A driver response follows this structure: ```json { "success": true, "service": { "name": "implementation-name" }, "result": "any type of value goes here", "metadata": {} } ``` There exists an example driver called `hello-world`. This driver implements a method called `greet` with the optional parameter `subject` which returns a string greeting either `World` (default) or the specified subject. ```javascript await puter.call('hello-world', 'no-frills', 'greet', { subject: 'Dave' }); ``` Let's break it down: #### `'hello-world'` `'hello-world'` is the name of an "interface". An interface can be thought of a contract of what inputs are allowed and what outputs are expected. For example the `hello-world` interface specifies that there must be a method called `greet` and it should return a string representing a greeting. To add another example, an interface called `weather` specify a method called `forcast5day` that always returns a list of 5 objects with a particular structure. #### `no-frills` `'no-frills'` is a simple - "no frills" (nothing extra) - implementation of the `hello-world` interface. All it does is return the string: ```javascript `Hello, ${subject ?? 'World'}!` ``` #### `'greet'` `greet` is the method being called. It's the only method on the `hello-world` interface. #### `{ subject: 'Dave' }` These are the arguments to the `greet` method. The arguments specify that we want to say "Hello" to Dave. Hopefully he doesn't ask us to open the pod bay doors, or if he does we hopefully have extensions to add a driver interface and driver implementation for the pod bay doors so that we can interact with them. ### Drivers in Extensions The `hellodriver` extension adds the `hello-world` interface like this: ```javascript extension.on('create.interfaces', event => { // createInterface is the only method on this `event` event.createInterface('hello-world', { description: 'Provides methods for generating greetings', methods: { greet: { description: 'Returns a greeting', parameters: { subject: { type: 'string', optional: true }, locale: { type: 'string', optional: true }, } } } }) }); ``` The `hellodriver` extension adds the `no-frills` implementation for `hello-world` like this: ```javascript extension.on('create.drivers', event => { event.createDriver('hello-world', 'no-frills', { greet ({ subject }) { return `Hello, ${subject ?? 'World'}!`; } }); });` ``` You can pass an instance of a class for a driver implementation as well: ```javascript class Greeter { greet ({ subject }) { return `Hello, ${subject ?? 'World'}!`; } } extension.on('create.drivers', event => { event.createDriver('hello-world', 'no-frills', new Greeter()); });` ``` Instances of classes being supported may seem to be implied by the example before this one, but that is not the case. What's shown here is that function members of the object passed to `createDriver` will not be "bound" (have their `.bind()` method called with a different object as the instance variable). ### Permission Denied When you try to access a driver as any user other than the default `admin` user, it will not work unless permission has been granted. The `hellodriver` extension grants permission to all clients using the following snippet: ```javascript extension.on('create.permissions', event => { event.grant_to_everyone('service:no-frills:ii:hello-world'); }); ``` The `create.permissions` event's `event` object has a few methods you can use depending on the desired granularity: - `grant_to_everyone` - grants permission to all users - `grant_to_users` - grants permission to only registered users (i.e. not to temporary/guest users)