Merge pull request #196 from thevahidal/deprecate-transaction-endpoint
This commit is contained in:
@@ -15,7 +15,7 @@ DB=foobar.db
|
|||||||
ACCESS_TOKEN_EXPIRATION_TIME=10H
|
ACCESS_TOKEN_EXPIRATION_TIME=10H
|
||||||
REFRESH_TOKEN_EXPIRATION_TIME=2D
|
REFRESH_TOKEN_EXPIRATION_TIME=2D
|
||||||
|
|
||||||
INITIAL_USER_USERNAME
|
INITIAL_USER_USERNAME
|
||||||
INITIAL_USER_PASSWORD
|
INITIAL_USER_PASSWORD
|
||||||
TOKEN_SECRET
|
TOKEN_SECRET
|
||||||
|
|
||||||
|
|||||||
@@ -157,12 +157,18 @@ npm run dev # Start the dev server
|
|||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
Set the `AUTH` variable to `true` in your `.env` file and use the command below to run the tests
|
1. Set the `AUTH` variable to true in your `.env` file.
|
||||||
|
2. Provide a username for the `INITIAL_USER_USERNAME` environment variable. The username should be a valid, meaningful username.
|
||||||
|
3. Provide a strong password for the `INITIAL_USER_PASSWORD` environment variable. The password should be at least 8 characters long and contain a combination of lowercase letters, uppercase letters, numbers, and special characters, for example: "Str0ng$Pw!".
|
||||||
|
4. Provider a secret for the `TOKEN_SECRET` environment variable.
|
||||||
|
5. Use the following command to run the tests:
|
||||||
|
|
||||||
```
|
```
|
||||||
npm run test
|
npm run test
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Make sure to replace the placeholders with the appropriate values for your environment.
|
||||||
|
|
||||||
## Community
|
## Community
|
||||||
|
|
||||||
[Join](https://bit.ly/soul-discord) the discussion in our Discord server and help making Soul together.
|
[Join](https://bit.ly/soul-discord) the discussion in our Discord server and help making Soul together.
|
||||||
|
|||||||
@@ -1,41 +1 @@
|
|||||||
## Root
|
## Root
|
||||||
|
|
||||||
### 1. Transaction
|
|
||||||
|
|
||||||
To start a transaction call `/transaction` endpoint with `POST` method.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
curl --request POST \
|
|
||||||
--url http://localhost:8000/api/transaction \
|
|
||||||
--header 'Content-Type: application/json' \
|
|
||||||
--data '{
|
|
||||||
"transaction": [
|
|
||||||
{
|
|
||||||
"statement": "INSERT INTO Artist (ArtistId, Name) VALUES (:id, :name)",
|
|
||||||
"values": { "id": 100000, "name": "Glen Hansard" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"query": "SELECT * FROM Artist ORDER BY ArtistId DESC LIMIT 1"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}'
|
|
||||||
```
|
|
||||||
|
|
||||||
Response
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"data": [
|
|
||||||
{
|
|
||||||
"changes": 1,
|
|
||||||
"lastInsertRowid": 100000
|
|
||||||
},
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"ArtistId": 100000,
|
|
||||||
"Name": "Glen Hansard"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "soul-cli",
|
"name": "soul-cli",
|
||||||
"version": "0.7.9",
|
"version": "0.8.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "soul-cli",
|
"name": "soul-cli",
|
||||||
"version": "0.7.9",
|
"version": "0.8.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bcrypt": "^5.1.1",
|
"bcrypt": "^5.1.1",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "soul-cli",
|
"name": "soul-cli",
|
||||||
"version": "0.7.9",
|
"version": "0.8.0",
|
||||||
"description": "A SQLite REST and Realtime server",
|
"description": "A SQLite REST and Realtime server",
|
||||||
"main": "src/server.js",
|
"main": "src/server.js",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ module.exports = {
|
|||||||
|
|
||||||
errorMessage: {
|
errorMessage: {
|
||||||
USERNAME_TAKEN_ERROR: 'This username is taken',
|
USERNAME_TAKEN_ERROR: 'This username is taken',
|
||||||
WEAK_PASSWORD_ERROR: 'This password is weak, please use another password',
|
WEAK_PASSWORD_ERROR:
|
||||||
|
'This password is weak, it should be at least 8 characters long and contain a combination of lowercase letters, uppercase letters, numbers, and special characters',
|
||||||
DEFAULT_ROLE_NOT_CREATED_ERROR:
|
DEFAULT_ROLE_NOT_CREATED_ERROR:
|
||||||
'Please restart soul so a default role can be created',
|
'Please restart soul so a default role can be created',
|
||||||
INVALID_USERNAME_PASSWORD_ERROR: 'Invalid username or password',
|
INVALID_USERNAME_PASSWORD_ERROR: 'Invalid username or password',
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ describe('Auth Endpoints', () => {
|
|||||||
|
|
||||||
expect(res.status).toEqual(400);
|
expect(res.status).toEqual(400);
|
||||||
expect(res.body.message).toBe(
|
expect(res.body.message).toBe(
|
||||||
'This password is weak, please use another password',
|
'This password is weak, it should be at least 8 characters long and contain a combination of lowercase letters, uppercase letters, numbers, and special characters',
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(res.body).not.toHaveProperty('password');
|
expect(res.body).not.toHaveProperty('password');
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
const db = require('../db/index');
|
|
||||||
const version = require('../../package.json').version;
|
const version = require('../../package.json').version;
|
||||||
|
|
||||||
// Root endpoint
|
// Root endpoint
|
||||||
const root = async (req, res) => {
|
const root = async (req, res) => {
|
||||||
/*
|
/*
|
||||||
#swagger.tags = ['Root']
|
#swagger.tags = ['Root']
|
||||||
#swagger.summary = 'Timestamp'
|
#swagger.summary = 'Timestamp'
|
||||||
#swagger.description = 'Endpoint to return server timestamp'
|
#swagger.description = 'Endpoint to return server timestamp'
|
||||||
*/
|
*/
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
@@ -18,77 +17,6 @@ const root = async (req, res) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Run any query transactions
|
|
||||||
// inspired by https://github.com/proofrock/ws4sqlite
|
|
||||||
// e.g. body:
|
|
||||||
// "transaction": [
|
|
||||||
// {
|
|
||||||
// "statement": "INSERT INTO users (id, firstName, lastName) VALUES (:id, :firstName, :lastName)",
|
|
||||||
// "values": { "id": 1, "firstName": "John", "lastName": "Doe" }
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "query": "SELECT * FROM users"
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// response:
|
|
||||||
// "data": [
|
|
||||||
// {
|
|
||||||
// "changes": 1,
|
|
||||||
// "lastInsertRowid": 1
|
|
||||||
// },
|
|
||||||
// [
|
|
||||||
// {
|
|
||||||
// "id": 1,
|
|
||||||
// "createdAt": "2022-10-10 10:55:29",
|
|
||||||
// "updatedAt": "2022-10-10 10:55:29",
|
|
||||||
// "firstName": "John",
|
|
||||||
// "lastName": "Doe"
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
// ]
|
|
||||||
//
|
|
||||||
|
|
||||||
const transaction = async (req, res) => {
|
|
||||||
/*
|
|
||||||
#swagger.tags = ['Root']
|
|
||||||
#swagger.summary = 'Transaction'
|
|
||||||
#swagger.description = 'Endpoint to run any transaction, e.g. [{ "query": "" }, { "statement": "", "values": {} }, { "query": "" }]',
|
|
||||||
#swagger.parameters['body'] = {
|
|
||||||
in: 'body',
|
|
||||||
required: true,
|
|
||||||
schema: { $ref: "#/definitions/TransactionRequestBody" }
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
const { transaction } = req.body;
|
|
||||||
const results = [];
|
|
||||||
try {
|
|
||||||
db.transaction(() => {
|
|
||||||
transaction.forEach((query) => {
|
|
||||||
if (query.statement) {
|
|
||||||
const { statement, values } = query;
|
|
||||||
const data = db.prepare(statement).run(values);
|
|
||||||
results.push(data);
|
|
||||||
} else if (query.query) {
|
|
||||||
const { query: queryString } = query;
|
|
||||||
const data = db.prepare(queryString).all();
|
|
||||||
results.push(data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
data: results,
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
res.status(400).json({
|
|
||||||
message: error.message,
|
|
||||||
error: error,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
root,
|
root,
|
||||||
transaction,
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,30 +14,3 @@ describe('Root Endpoints', () => {
|
|||||||
expect(res.body.data).toHaveProperty('timestamp');
|
expect(res.body.data).toHaveProperty('timestamp');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Transaction Endpoint', () => {
|
|
||||||
it('POST /transaction should commit transaction and return an array of changes and lastInsertRowid', async () => {
|
|
||||||
const res = await requestWithSupertest.post('/api/transaction').send({
|
|
||||||
transaction: [
|
|
||||||
{
|
|
||||||
statement: `CREATE TABLE students (id INTEGER PRIMARY KEY, firstName TEXT, lastName TEXT)`,
|
|
||||||
values: {},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
statement: `INSERT INTO students (id, firstName, lastName) VALUES (:id, :firstName, :lastName)`,
|
|
||||||
values: { id: 1, firstName: 'John', lastName: 'Doe' },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
query: `SELECT * FROM students`,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(res.status).toEqual(200);
|
|
||||||
expect(res.type).toEqual(expect.stringContaining('json'));
|
|
||||||
expect(res.body).toHaveProperty('data');
|
|
||||||
expect(res.body.data).toEqual(expect.any(Array));
|
|
||||||
expect(res.body.data[0]).toHaveProperty('changes');
|
|
||||||
expect(res.body.data[0]).toHaveProperty('lastInsertRowid');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -1,16 +1,9 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
|
|
||||||
const controllers = require('../controllers/index');
|
const controllers = require('../controllers/index');
|
||||||
const { validator } = require('../middlewares/validation');
|
|
||||||
const schema = require('../schemas/index');
|
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
router.get('/', controllers.root);
|
router.get('/', controllers.root);
|
||||||
router.post(
|
|
||||||
'/transaction',
|
|
||||||
validator(schema.transaction),
|
|
||||||
controllers.transaction
|
|
||||||
);
|
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|||||||
@@ -152,7 +152,8 @@ const doc = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
WeakPasswordErrorResponse: {
|
WeakPasswordErrorResponse: {
|
||||||
message: 'This password is weak, please use another password',
|
message:
|
||||||
|
'This password is weak, it should be at least 8 characters long and contain a combination of lowercase letters, uppercase letters, numbers, and special characters',
|
||||||
},
|
},
|
||||||
|
|
||||||
UsernameTakenErrorResponse: {
|
UsernameTakenErrorResponse: {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"swagger": "2.0",
|
"swagger": "2.0",
|
||||||
"info": {
|
"info": {
|
||||||
"version": "0.7.2",
|
"version": "0.8.0",
|
||||||
"title": "Soul API",
|
"title": "Soul API",
|
||||||
"description": "API Documentation for <b>Soul</b>, a SQLite REST and realtime server. "
|
"description": "API Documentation for <b>Soul</b>, a SQLite REST and realtime server. "
|
||||||
},
|
},
|
||||||
@@ -54,31 +54,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/api/transaction": {
|
|
||||||
"post": {
|
|
||||||
"tags": ["Root"],
|
|
||||||
"summary": "Transaction",
|
|
||||||
"description": "Endpoint to run any transaction, e.g. [{ \"query\": \"\" }, { \"statement\": \"\", \"values\": {} }, { \"query\": \"\" }]",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "body",
|
|
||||||
"in": "body",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/TransactionRequestBody"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK"
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Bad Request"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/tables/": {
|
"/api/tables/": {
|
||||||
"get": {
|
"get": {
|
||||||
"tags": ["Tables"],
|
"tags": ["Tables"],
|
||||||
|
|||||||
Reference in New Issue
Block a user