Set up REST automatically
npm install @carlosjimenohernandez/restomaticAutomatic REST on top of Node.js + SQLite + Express.
``sh`
npm i -g @carlosjimenohernandez/restomatic
- REST operations:
- select: at /api/v1/data/select/api/v1/data/insert?token=admin
- insert: at /api/v1/data/update?token=admin
- update: at /api/v1/data/delete?token=admin
- delete: at /api/v1/data/createTable?token=admin
- createTable: at /api/v1/data/createColumn?token=admin
- createColumn: at /api/v1/data/removeTable?token=admin
- removeTable: at /api/v1/data/removeColumn?token=admin
- removeColumn: at /api/v1/data/setFile?token=admin
- setFile: at /static/...
- Static files: /template/...
- to load js, css, images, etc.
- Dynamic templates: ejs
- to load custom -rendered content./api/v1/filesystem/readDirectory?token=admin
- Filesystem operations:
- readDirectory: at /api/v1/filesystem/makeDirectory?token=admin
- makeDirectory: at /api/v1/filesystem/deleteDirectory?token=admin
- deleteDirectory: at /api/v1/filesystem/readFile?token=admin
- readFile: at /api/v1/filesystem/writeFile?token=admin
- writeFile: at /api/v1/filesystem/deleteFile?token=admin
- deleteFile: at /api/v1/filesystem/isFile?token=admin
- isFile: at
This is part of the package.json:
`json`
"dependencies": {
"better-sqlite3": "^12.2.0",
"body-parser": "^2.2.0",
"ejs": "^3.1.10",
"express": "^5.1.0",
"multer": "^2.0.2",
"sqlstring": "^2.3.3"
}
You have 2 options to run restomatic:
- From command line
- From node.js script
Both are explained below.
From command line you can:
`sh`
npx restomatic
--port "9090" # Port to listen
--models "models.js" # Models to import
--routes "routes.js" # Routes to include beside defaults
--token "admin" # Token for advanced operations
--database "test.sqlite" # File for database
From a node.js script you can:
`js`
const restomaticInstance = await require("@carlosjimenohernandez/restomatic").create({
port: "9090",
models: "models.js",
routes: "routes.js",
token: "admin",
database: "test.sqlite",
});
The previous calls overstand some meaningful parameters, which are explained below.
You specify the port number which must open the instance.
The token parameter is used to filter advanced operations that require permissions, like:/api/v1/data/insert
- /api/v1/data/update
- /api/v1/data/delete
- /api/v1/data/createTable
- /api/v1/data/createColumn
- /api/v1/data/removeTable
- /api/v1/data/removeColumn
- /api/v1/filesystem/makeDirectory
- /api/v1/filesystem/readDirectory
- /api/v1/filesystem/deleteDirectory
- /api/v1/filesystem/writeFile
- /api/v1/filesystem/readFile
- /api/v1/filesystem/deleteFile
- /api/v1/filesystem/isFile
-
You have to provide directly the string that can match the token parameter on the request, either by, in this order:request.headers.token
- request.body.token
- request.query.token
-
You specify the file that will be used (or created) as sqlite database.
On models.js you must have something like:
`js`
module.exports = {
individuals: {
columns: {
nombre: { sql: "VARCHAR(255) UNIQUE", },
edad: { sql: "VARCHAR(255)", },
tipo: { sql: "VARCHAR(255)", },
padre: { sql: "INTEGER REFERENCES individuals(id)" }
}
}
};
On routes.js you will want to have something like:
`js`
Restomatic.router.use("/path", function(request, response) {
try {
return response.success({
message: "Your message",
note: "This method is injected by «XXX.create-application.js»'
});
} catch(error) {
return response.success(new Error("This method is injected by «XXX.create-application.js» too"));
}
});
And a REST is set up for you automatically.
The following titles describe the common operations enabled by default on /api/v1/data/{operation} path of the application.
- Schema at /api/v1/data/schema/api/v1/data/select
- Select data at from
- Parameter : Stringwhere
- with the name of the table
- Parameter : Arrayorder
- with the conditions
- Parameter : Array!
- with the columns in order
- Can use to reverse the orderpage
- Parameter : Integer1
- with the page
- Starts on items
- Parameter : Integer100
- Defaults to /api/v1/data/insert
- Insert data at into
- Parameter : Stringvalues
- with the name of the table
- Parameter : Array | Object/api/v1/data/update
- with the values for the new object/s
- Update data at from
- Parameter : Stringwhere
- with the name of the table
- Parameter : Arrayset
- with the conditions
- Parameter : Object/api/v1/data/delete
- with the new values
- Delete data at from
- Parameter : Stringwhere
- with the name of the table
- Parameter : Array
- with the conditions
Also, you can alter the schema by the following operations:
- Create table at /api/v1/data/createTabletable
- Parameter : Stringcontent
- with the name of the table
- Parameter : String/api/v1/data/createColumn
- with the SQLite code of the table
- Create column at table
- Parameter : Stringcolumn
- with the name of the table
- Parameter : Stringcontent
- with the name of the column
- Parameter : String/api/v1/data/removeTable
- with the SQLite code of the column
- Remove table at table
- Parameter : String/api/v1/data/removeColumn
- with the name of the table
- Remove column at table
- Parameter : Stringcolumn
- with the name of the table
- Parameter : String/api/v1/data/setFile
- with the name of the column
- Set file at multipart/form-data
- This operation requires (see test/run.js)file
- Parameter : Blob
- with the contents of the file
Also, you can access and modify the filesystem (only /static and /template folders) by the following operations:
- Read file at /api/v1/filesystem/readFilepath
- Parameter : String/api/v1/filesystem/writeFile
- Write file at path
- Parameter : Stringcontent
- Parameter : String/api/v1/filesystem/deleteFile
- Delete file at path
- Parameter : String/api/v1/filesystem/readDirectory
- Read directory at path
- Parameter : String/api/v1/filesystem/makeDirectory
- Make directory at path
- Parameter : String/api/v1/filesystem/deleteDirectory
- Delete directory at path
- Parameter : String/api/v1/filesystem/isFile
- Is file at path
- Parameter : String
You can select (without admin token):
`js`
const res = await fetch("http://127.0.0.1:9090/api/v1/data/select", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
token: "none", // This is not required for select operations
from: "individuals",
where: [
["id", "is not null"],
["id", "!=", "1000"],
["id", ">=", "1"],
["id", ">", "0"],
["id", "<", "1000"],
["id", "<=", "1000"],
["id", "like", "%"],
["id", "not like", "x%"],
["id", "in", [1,2,3]],
["id", "not in", [4,5,6]],
],
order: ["!id"] // with ! for DESC [endant]
page: 1, // defaults to 1
items: 100, // defaults to 100
})
});
console.log(await res.json());
Once running, you can insert with admin token:
`js`
const res = await fetch("http://127.0.0.1:9090/api/v1/data/insert", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
token: "admin", // This has to match with provided cmd token
into: "individuals",
values: [{
nombre: "Carlos Jimeno Hernández",
edad: 35
}, {
nombre: "Ada Jimeno Hernández",
edad: 9,
}, {
nombre: "Gatito Jimeno Hernández",
edad: 4,
}]
})
});
console.log(await res.json());
You can update with admin token:
`js`
const res = await fetch("http://127.0.0.1:9090/api/v1/data/select", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
token: "admin", // This has to match with provided cmd token
from: "individuals",
set: {
tipo: "Familiar"
},
where: [
["id", "is not null"],
["id", "!=", "1000"],
["id", ">=", "1"],
["id", ">", "0"],
["id", "<", "1000"],
["id", "<=", "1000"],
["id", "like", "%"],
["id", "not like", "x%"],
["id", "in", [1,2,3]],
["id", "not in", [4,5,6]],
]
})
});
console.log(await res.json());
You can delete with admin token:
`js`
const res = await fetch("http://127.0.0.1:9090/api/v1/data/delete", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
token: "admin", // This has to match with provided cmd token
from: "individuals",
where: [
["id", "is null"],
["id", "!=", "1000"],
["id", ">=", "1"],
["id", ">", "0"],
["id", "<", "1000"],
["id", "<=", "1000"],
["id", "like", "%"],
["id", "not like", "x%"],
["id", "in", [1,2,3]],
["id", "not in", [4,5,6]],
]
})
});
console.log(await res.json());
For example, using GET:
http://127.0.0.1:9090/api/v1/data/createTable?token=admin&table=lote
Or using POST:
`js
const res = await fetch("http://127.0.0.1:9090/api/v1/data/createTable", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
token: "admin", // This has to match with provided cmd token
table: "lote",
content:
numero INTEGER UNIQUE NOT NULL,
contenedor INTEGER REFERENCES lote(id)
`
})
});
console.log(await res.json());
For example:
`jsVARCHAR(255) NOT NULL
const res = await fetch("http://127.0.0.1:9090/api/v1/data/createColumn", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
token: "admin", // This has to match with provided cmd token
table: "lote",
column: "identificador",
content: `
})
});
console.log(await res.json());
For example:
`js`
const res = await fetch("http://127.0.0.1:9090/api/v1/data/removeTable", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
token: "admin", // This has to match with provided cmd token
table: "lote",
})
});
console.log(await res.json());
For example:
`js`
const res = await fetch("http://127.0.0.1:9090/api/v1/data/removeTable", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
token: "admin", // This has to match with provided cmd token
table: "lote",
column: "identificador",
})
});
console.log(await res.json());
Below are listed other features the tool offers automatically.
- Static content
- Dynamic content
- Upload files
You can access the files under src/static by:
http://127.0.0.1/static/whatever.txt
You can access the files under src/template by:
http://127.0.0.1/static/whatever.ejs
They will always be rendered as ejs files.
You can access the following variables:
- requestresponse
- Restomatic
-
You can use this snippet to force some mime-type when rendering and serving a file, and so, load css or html or any, but dynamically:
`html`
<% response.type("html") %>
<% response.type("css") %>
<% response.type("js") %>
Only admin can upload files, as it is a potentially conflictive behaviour.
The example run on test/run.js demonstrates how this can work without downloading libraries in node.js:
`js
const fs = require("fs");
const form = new FormData();
const fileBuffer = fs.readFileSync(__dirname + "/example.txt");
form.append("file", new Blob([fileBuffer]), "example.txt");
const r = await fetch("http://127.0.0.1:9090/api/v1/data/setFile", {
method: "POST",
body: form,
headers: {
token: "admin"
}
});
const response = await r.text();
console.log(response);
`
Only admin can commit filesystem operations, as they have potentially conflictive behaviours.
For example:
`js`
const res = await fetch("http://127.0.0.1:9090/api/v1/filesystem/makeDirectory", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
token: "admin", // This has to match with provided cmd token
path: "/static/newdir", // This has to start with /static or /template
})
});
console.log(await res.json());
For example:
`js`
const res = await fetch("http://127.0.0.1:9090/api/v1/filesystem/readDirectory", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
token: "admin", // This has to match with provided cmd token
path: "/static/newdir", // This has to start with /static or /template
})
});
console.log(await res.json());
For example:
`js`
const res = await fetch("http://127.0.0.1:9090/api/v1/filesystem/deleteDirectory", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
token: "admin", // This has to match with provided cmd token
path: "/static/newdir", // This has to start with /static or /template
})
});
console.log(await res.json());
For example:
`js`
const res = await fetch("http://127.0.0.1:9090/api/v1/filesystem/writeFile", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
token: "admin", // This has to match with provided cmd token
path: "/static/newdir/file1.txt", // This has to start with /static or /template
content: "Hello!",
})
});
console.log(await res.json());
For example:
`js`
const res = await fetch("http://127.0.0.1:9090/api/v1/filesystem/readFile", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
token: "admin", // This has to match with provided cmd token
path: "/static/newdir/file1.txt", // This has to start with /static or /template
})
});
console.log(await res.json());
For example:
`js`
const res = await fetch("http://127.0.0.1:9090/api/v1/filesystem/deleteFile", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
token: "admin", // This has to match with provided cmd token
path: "/static/newdir/file1.txt", // This has to start with /static or /template
})
});
console.log(await res.json());
For example:
`js`
const res = await fetch("http://127.0.0.1:9090/api/v1/filesystem/isFile", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
token: "admin", // This has to match with provided cmd token
path: "/static/jquery.js", // This has to start with /static or /template
})
});
console.log(await res.json());
The npm run build command takes bundlelist.js exported files and dumps them in a all-in-one file called restomatic.js.
By this reason, all the files have its __dirname` pointing on top of the project.
Use it at your own convenience, the final file is quite short.