-
Notifications
You must be signed in to change notification settings - Fork 3.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
🚀 Feature: Local functions server #5425
Comments
Hi @byawitz - thank you for opening this. We do realise that this method of testing a function has scope of improvement. Leaving this issue open for now to gather community feedback and suggestions. |
You can look here for a real-use example. |
Hello @byawitz |
@Emeka212 Thanks |
Thanks for the workaround, I have modified it a little for handling multiple functions and variables for them separately Instructions
Usage
if (process.argv.length < 2) {
process.exit();
}
const fs = require('fs');
const dotenv = require("dotenv")
let path = process.argv[2].split('/');
if (path[path.length - 1] === 'index.js') path = path.join('/');
if (path[path.length - 1] === 'src') path = path.join('/');
if (path.length > 1) path = `${path.join('/')}`;
if (path.length === 1) path = `./functions/${path}/src`;
// eslint-disable-next-line import/no-dynamic-require
const func = require(path);
// eslint-disable-next-line import/no-dynamic-require
const customReq = fs.existsSync(`${path}/../req.js`) ? require(`${path}/../req.js`) : {};
const req = {
headers: {},
payload: {},
variables: {
...process.env, // add env vars
APPWRITE_FUNCTION_ID : '',
APPWRITE_FUNCTION_NAME : '',
APPWRITE_FUNCTION_DEPLOYMENT : '',
APPWRITE_FUNCTION_TRIGGER : '',
APPWRITE_FUNCTION_RUNTIME_NAME : '',
APPWRITE_FUNCTION_RUNTIME_VERSION: '',
APPWRITE_FUNCTION_EVENT : '',
APPWRITE_FUNCTION_EVENT_DATA : '',
APPWRITE_FUNCTION_DATA : '',
APPWRITE_FUNCTION_PROJECT_ID : '',
APPWRITE_FUNCTION_USER_ID : '',
APPWRITE_FUNCTION_JWT : '',
},
...customReq, // override req
};
const res = {
send(text, status) {
console.log(text, status);
},
json(obj, status) {
console.log(obj, status);
},
};
func(req, res).then(); UPDATE: New Functions const main = async () => {
if (process.argv.length < 3) {
console.log('Invalid Usage');
return;
}
let path = process.argv[2].split('/');
if (path[path.length - 1] === 'index.js') path = path.join('/');
if (path[path.length - 1] === 'src') path = path.join('/');
if (path.length > 1) path = `${path.join('/')}`;
if (path.length === 1) path = `./functions/${path}/src`;
// eslint-disable-next-line global-require
require('dotenv').config({ path: `${path}/../.env` });
// eslint-disable-next-line import/no-dynamic-require
const func = await import(`${path}/main.js`);
const req = {
method: 'POST',
body: {
name: 'test',
status: 'unregistered',
owner: null,
model: null,
delete: false,
battery: null,
carrierName: null,
signalStrength: null,
lastSeen: null,
$id: '',
$permissions: [],
$createdAt: '2023-09-22T20:34:32.293+00:00',
$updatedAt: '2023-09-22T20:34:32.293+00:00',
$databaseId: '',
$collectionId: '',
},
headers: {
host: ':3000',
'user-agent': 'Appwrite/1.4.3',
'x-appwrite-trigger': 'event',
'x-appwrite-event': 'databases.sms-api.*.*.documents.*.create',
'x-appwrite-user-id': '',
'content-type': 'application/x-www-form-urlencoded',
connection: 'keep-alive',
'content-length': '339',
},
};
const res = {
send(text, status) {
console.log('[SEND] ', text, status);
},
json(obj, status) {
console.log('[JSON] ', obj, status);
},
};
const log = (...args) => console.log('[LOG] ', ...args);
const error = (...args) => console.error('[ERR] ', ...args);
func.default({ req, res, log, error }).then();
};
main(); |
@byawitz I spent some time to make this functionality work, and they updated the functions !! 😂😂 |
@harshsinghvi Oops, Yes they just did, and also in the cloud. |
I followed the mentioned guidelines, but it still doesn't work. The functions-starter is not updated with the new syntax EDIT: They have mentioned in the guide to use import/exports but it throws errors
|
Finally, my code works, there was an issue with new const main = async () => {
if (process.argv.length < 3) {
console.log('Invalid Usage');
return;
}
let path = process.argv[2].split('/');
if (path[path.length - 1] === 'index.js') path = path.join('/');
if (path[path.length - 1] === 'src') path = path.join('/');
if (path.length > 1) path = `${path.join('/')}`;
if (path.length === 1) path = `./functions/${path}/src`;
// eslint-disable-next-line global-require
require('dotenv').config({ path: `${path}/../.env` });
// eslint-disable-next-line import/no-dynamic-require
const func = await import(`${path}/main.js`);
const req = {
method: 'POST',
body: {
name: 'test',
status: 'unregistered',
owner: null,
model: null,
delete: false,
battery: null,
carrierName: null,
signalStrength: null,
lastSeen: null,
$id: '',
$permissions: [],
$createdAt: '2023-09-22T20:34:32.293+00:00',
$updatedAt: '2023-09-22T20:34:32.293+00:00',
$databaseId: '',
$collectionId: '',
},
headers: {
host: ':3000',
'user-agent': 'Appwrite/1.4.3',
'x-appwrite-trigger': 'event',
'x-appwrite-event': 'databases.sms-api.*.*.documents.*.create',
'x-appwrite-user-id': '',
'content-type': 'application/x-www-form-urlencoded',
connection: 'keep-alive',
'content-length': '339',
},
};
const res = {
send(text, status) {
console.log('[SEND] ', text, status);
},
json(obj, status) {
console.log('[JSON] ', obj, status);
},
};
const log = (...args) => console.log('[LOG] ', ...args);
const error = (...args) => console.error('[ERR] ', ...args);
func.default({ req, res, log, error }).then();
};
main(); |
🔖 Feature description
An easy way to build and test functions locally.
Currently, when developing a function, it is necessary to deploy and upload it to the server to fully test it.
Although in the last step of a function development process, I'll probably deploy it and test it on the Appwrite instance a few times, It would be much easier to try it locally.
What I thought could be a good solution is to add a local server script to each one of the function-starter templates.
For example, in the Node template, we can add a file named
local-server.js
:├── node-18.0 │ ├── src │ │ ├── index.js │ ├── .gitignore │ ├── package.json │ ├── README.md │ ├── local-server.js !New file
Then this could be the format of
package.json
:And this would be the code of
local-server.js
(a suggestion):Then it is just a matter of running the
local-server.js
file in one of these ways.Being able to quickly mock any of the Appwrite variables in a local environment sounds like something that can make the development process of functions much fast.
P.s. in the future it's also open the option to support HMR whenever possible.
🎤 Pitch
A lot of times, the process of developing a function can be one time task.
But, from my experience, it usually requires many test execution. Using the previous solution will make it much easier to develop any function in almost no time.
👀 Have you spent some time to check if this issue has been raised before?
🏢 Have you read the Code of Conduct?
The text was updated successfully, but these errors were encountered: