
Research
Supply Chain Attack on Axios Pulls Malicious Dependency from npm
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.
Restdone - simplify RESTful service
Restdone is powering the following technlogies
It's a core of RESTful services. Resources are available at a specific path on the server. For example: "/api/users".
In the best traditions of REST-genre the most of the actions with resource can be "expressed" with http-methods.
restdone supports following methods:
Get collection (select) - retrieve all resources in a collection
http GET <serverURL>/api/<collection>
Get resource (selectOne) - retrieve a single resource with specified
http GET <serverURL>/api/<collection>/<id>
restdone allows to get the list of resources according provided criteria. If no criteria provided, it return the
first page of maxPageSize with all available fields.
Example:
http GET localhost:3000/api/users?filter={"username": "test"}&fields=username,createdAt&orderBy={"username": -1}
The set of supported parameters is determined by the data source.
It's json value containing any valid MongoDB query. See docs for details.
Example:
http GET localhost:3000/api/users?filter={"gender": "M", "age": { "$gt": 18 }}
You can use regex values in filter. As we pass JSON in this param it's not possible to use regular expression objects (/pattern/).
You should replace it with $regex operator. See docs for details.
Comma separated list of field names.
Example:
http GET localhost:3000/api/users?fields=gender,age
It's json value built according MongoDB rules. Use 1 for an ascending sorting, and -1 for a descending sorting. See docs for details.
Example:
http GET localhost:3000/api/users?orderBy={"username": 1, "age": -1}
The maximum number of records in the response. defaultPerPage is used by default, and maximum is limited with maxPerPage. See docs for details.
Example:
http GET localhost:3000/api/users?per_page=10
A number of page to return, 1 if a value is not provided. We skip (page - 1) * per_page records in the query to achieve that. See docs for details.
Parameter for q-searches. It can be any string value.
restdone will use it to build the following condition for every value in your qFields:
{$regex: '.*' + q + ".*", $options: 'i'}
Example:
http GET localhost:3000/api/users?q=John
See q-search section for details.
Comma separated list of field names.
In order to filter records to fetch from the server you can specify filter param in URL of your request. It's json
value containing any valid sequelize.js query. Besides simple
filtering by values it supports additional operators, which allow to build more complex query to the server. See
docs for more details.
Example:
http GET localhost:3000/api/users?filter={"gender": "M", "age": { "$gt": 18}, "name": {"$like": "Ro%"}}
Every fetching request returns only one page of data. You can change default page size providing perPage param in URL.
Default value of the page is 25, and the maximum page size limited by 100.
The page param allows you to specify page number to fetch. The page numeration begins from 1.
For ordering the records you should use orderBy param in URL. It should be a valid JSON, containing field names as
keys, and 1 or -1 as values depending on a way to sort (ASC or DESC).
http POST localhost:3000/api/users username=test password=pass
It allows to add new resources to the server. You can provide field values in body with json, or as form params.
http PUT localhost:3000/api/users/<id> username=test password=pass
It completely replaces resource with provided id with new one specifided in the request. You can provide field values in body with json, or as form params.
Be careful if no value for a field provided, it will be set to undefined.
http PATCH localhost:3000/api/users/<id> password=pass
It partially update resource with provided id with data from the request. You can provide field values in body with json, or as form params.
If a resource returns an array of associated entity, it’s possible to perform special kind of PATCH request with special array methods.
The server supports the following methods:
$push - add new associated items,
$pull - remove existing associated items.
The body of the method can be different among the resources. Please, refer to resource documentation: mongo.
Example: Add tag to the message tags
http PATCH <serverURL>/api/messages/<messageId> Authorization:'Bearer <access_token>'
{
$push: {
tags: {
tagId: 15
}
}
}
http DELETE 'localhost:3000/api/users/<id>'
It removes the record by id.
As an extension to standard rest-kit.
http GET localhost:3000/api/users/count?filter={age: { $gt: 18 } }}
It allows to get count of records of specified resource. See docs for details.
It's json value containing any valid MongoDB query. See docs for details.
Example:
{"gender": "M", age: { $gt: 18 } }}
It relates to getting the list of resources. Every such response is limited with paging rules:
per_page and page params in URL,restdoneOptions.defaultPerPage),per_page greater then restdoneOptions.maxPerPage, value of maxPerPage is used.Controllers are the way to provide needed configuration for your resource and to customize its behaviour.
This param is a way to specify, what data source will be used. Today available restdone-mongoose and restdone-sequelize modules. Any resource is bound to mongoose/sequelize model, and this param is a way to specify, what the model your resource uses.
TODO: Put details about transport
Example (mongoose):
const Restdone = require('restdone');
const User = require('MongooseUserModel');
class UserController extends Restdone.Controller {
constructor(options) {
let publicFields = ['firstName', 'lastName', 'thumbnailUrl'];
options = options || {};
Object.assign(options, {
dataSource: {
type: 'mongoose',
options: {
model: User
}
},
path: '/api/users'
});
super(options);
...
});
Example (sequelize):
const Restdone = require('restdone');
const User = require('SequelizeUserModel');
class UserController extends Restdone.Controller {
constructor(options) {
let publicFields = ['firstName', 'lastName', 'thumbnailUrl'];
options = options || {};
Object.assign(options, {
dataSource: {
type: 'sequelize',
options: {
model: User
}
},
path: '/api/users'
});
super(options);
...
});
With this option you specify the paths, where resource will be available at. There are 2 important points:
For instance, you can write:
path: ['/api/appData', '/api/users/:owner/appData']
and in the case if an user requests data at /api/users/543d2605e21f85d73b060979/appData, appData will be filtered by provided value of owner.
By default all the fields you defined in your model schema (without fields with name starting from "__") are available in your resource. Providing this params are you able exclude some fields from the resource, or add new calculated fields.
If true, restricts returned and saved fields with fields array. Default value is true.
Name of id field. By default: '_id'. This value is used in route params for selectOne, replace, update, delete.
With this param you can specify default filter value for your controller.
With this param you can specify default orderBy value for your controller.
For example:
orderBy: {date: -1}
Q-search allows to search data without specifying exact fields of search. Just specify in your controller searchable fields:
qFields: ["login", "firstName", "lastName"]
and set q param of your GET request (see q for details).
Available only for restdone-mongoose data source.
Supported methods with arrays. Default value: ['$addToSet', '$pop', '$push', '$pull']. It's relevant to update (PATCH) only. You can specify such methods in order to manipulate array fields of your resource.
The params and implementations of these methods relate to the same methods in MongoDB:
You can customize the behavior of your controllers very much. And we did all our best to make this process as simple as it's possible.
That's why you're able to specify an option in one of the methods, and restdone will apply inheritance rules to the of other methods.
Rules:
default ->
select ->
selectOne
insert ->
update ->
replace
delete
count
For example, if you want to define pre processor for insert, update, partialUpdate, delete that's enough to define it
in your insert:
var YourController = Restdone.Controller.extend({
...
insert: {
pre: function (req, res, next) {
...
}
}
All handlers receive scope in params, where you can get req for example. In return you can use a promise.
pre(scope)
pre is a preprocessor that is executed at the beginning before any other logic runs. It's a good point to check the preconditions of your request. For example, check if Admin executes the request:
pre: function (scope) {
// not admin
if (!this.isAdmin(scope.req)) {
throw HTTP_STATUSES.FORBIDDEN.createError();
}
}
Also, you can specify pre-handler on action level, and it will be ran instead.
collectionPost(collection, scope)
When select returns any collection from db, this collection is passed through this postprocessor.
It's a good point if you want to manipulate the set of items of the collection, but not with items by themselves.
Also, you can specify collectionPost-handler on action level, and it will be ran instead.
post(resource, scope)
post is postprocessor. It runs immediately before a resource is sent to an user.
At this point you can change the resource by itself. For instance, you can fill calculated fields here:
post: function (resource, scope) {
if (resource.icon) {
resource.icon_url =
scope.req.protocol + "://" + scope.req.get('host') + '/api/resource/' + resource._id + '/icon';
}
return resource;
}
Additionally you can specify post-handler on action level, and it will be ran instead.
queryPipe: function (query, scope)
You can use queryPipe if you need to call additional methods at data source query
(docs).
This method is called after all restdone calls are done, but immediately before exec.
Draw your attention, this method is called in 2 different semantics:
callback,query.
In order to make your method workable in both semantics use the way from example bellow (return and call callback at the same line).So, in this example we put populate to our query pipe:
queryPipe: function (query, req, res, callback) {
return query.populate("fieldToPopulate", callback);
}
prepareData: function (scope)
Prepares data to create new document.
It's a point you can specify defaults for your resource when restdone creates it. Returning promise should contain
data - object containing default values of resource fields.
If you do not specify the handler, restdone uses {} to init the object.
beforeAssignFields: function (scope)
If it's defined, it runs immediately before assignFields, and has the same params.
You can use it to define what the params will be set.
beforeSave: function (scope)
Handler, called when you create new resource or change existing instance of your resource after all assignments are already done, but immediately before saving it to your database
afterSave: function (scope)
If it's defined, it runs immediately after saveDocument, and has the same params.
afterChange: function (scope)
Very similar to afterSave, it calls immediately after it in inserts and updates, but it runs after deletes as well.
It can be a good point to integrate your kind of triggerEngine. For instance, you can define something like that in
a base controller class of your application:
afterChange: function (scope) {
redisClient.publish(this.ModelClass.modelName + '.' + scope.model.id, scope.action);
}
After that you will be able to subscribe to those events and handle them in flexible and scalable way.
beforeDelete: function (scope)
If it's defined, it runs immediately before removing the document.
beforeArrayMethod(queryParam, methodName, fieldName, scope)
If it's defined, it runs immediately before proceeding of array methods.
It's used to create context, if it's defined. Otherwise, {} used.
Here you can specify a way, how exceptions will be converted to response.
assignFields(scope)
Assigns all fields from scope.source to scope.model.
You can fetch any additional data at this point, or completely change the way fields are assigned.
Default implementation iterates through all the fields, passing them through assignFilter, and calling assignField.
assignField(fieldName, scope)
Assigns single field with name fieldName from scope.source to scope.model.
At this point you have enough data to deny assigning of exact values to exact fields for instance:
class YourController extends Restdone.Controller {
assignField(fieldName, scope) {
if (fieldName == 'status' && scope.source[fieldName] == STATUSES.RESTRICTED_STATUS) {
throw HTTP_STATUSES.FORBIDDEN.createError('It\'s not allowable to set restricted status');
}
return super.assignField(fieldName, scope);
},
}
assignFilter(queryParams, fieldName, scope)
Filters assigning field with name fieldName.
In this method you can synchronously return true / false, allowing / denying to assign exact fields.
For example you can silently skip changing of exact fields for non-admin users:
class YourController extends Restdone.Controller {
assignFilter(queryParams, fieldName, scope) {
if (fieldName === 'adminOnlyField') {
return this.isAdmin(req);
}
return super.assignField(fieldName, scope);
},
}
createDocument: function (scope)
Create new document instance, called when you create new instance of your resource after all assignments are already done, but immediately before saving it to your database.
saveDocument: function (scope)
Saves document to db, called in inserts and updates.
restdoneOptions allows you to define common options for all the controllers of your app.
This value is used in all select requests if no per_page/perPage has been provided. Default value is 25.
This value restricts maximum value of per_page/perPage supported with your app. Default value is 100.
The module uses e2e tests. In order to run them you should start the testing server:
npm run express
Then run:
$ npm test
FAQs
Restful database-agnostic service
We found that restdone demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.

Research
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.

Security News
TeamPCP is partnering with ransomware group Vect to turn open source supply chain attacks on tools like Trivy and LiteLLM into large-scale ransomware operations.