npm package: @simplus/facades-scopes
Description: Add scopes to facades for better data handling
Author: Yehudi Hollevoet
Latest version: 1.0.3

# Facade scopes

Facades scopes allow to control what parameters are created, updated and fetched from the database using facades.

## Install

```
npm install @simplus/facades-scopes
```

## How does it work ?

The library only provides a decorator called __collectionScopes__, the decorator adds a method to facadae classes.

the decorator receives a set of object associated to their names. I will show how the library works through a real example.

Let's imagine we have a database full of users, and these users have different types of roles. (one user is an admin, an other user is normal user, and the last one is an anonymous user).

we will create three different type of scopes: __public__ (for everyone), __user__ (for authenticated users) and __admin__ (for admins)

this is how our Schema looks alik:
```typescript
const schema = {
	_id : { dataType : String},
	name: { dataType : String},
	email: { dataType : String},
	blacklisted: { dataType : Boolean},
	password: { dataType : String},
}
```

let's start with a simple configuration:
```typescript
const scopes = {
	public: ['_id', 'name'], // pulbic can only see _id and name
	user : ['_id', 'name', 'email'], // ...
	admin : ['_id', 'name', 'email', 'blacklisted'] // ...
}
```

We will now configure out Facade

```typescript
@collectionScopes(scopes)
export class UserFacade extends SQLCollection<User> {
}


export userFacade = new UserFacade({...})
```

That's it, now the only thing to do is to fetch the right scope during a request

```typescript
// Fetch list of users
app.get('/users/', (req, res, next) => {
	let scope = 'public'
	if(req.user) // user is logged in
		scope = 'user'
	if(req.user.role === 'admin')
		scope = 'admin'
	userFacade.scope(scope).find({}).then( ... )
})
// Fetch one user
app.get('/users/:id', (req, res, next) => {
	let scope = 'public'
	if(req.user) // user is logged in
		scope = 'user'
	if(req.user.role === 'admin')
		scope = 'admin'
	if(req.user.id === req.params.id)
		scope = null
	userFacade.scope(scope).findById(req.params.id).then( ... )
})
```

Let's now imagine we want to make a specific requeqt with a specific scope (let's imagine someone has a token to access all the information of an user)

```typescript
app.get('/users/:id/special-request/:token', (req, res, next) => {
	if(!isValid(req.params.token))
		return next(new Error())
	let scope = parseToken(req.params.token) // for example ['email', 'password']
	userFacade.scope(scope).findById(req.params.id).then( ... )
})
```

The next item you might want to do in some cases is blacklist items instead of white list them, that is the second parameter of the scope function
```typescript
app.get('/users/:id/everything-but-password', (req, res, next) => {
	userFacade.scope(null, ['password']).findById(req.params.id).then( ... )
})
```

### What about creation and updates ?

it works the same way, only you limit the input instead of the output

```typescript
app.put('/users/:id/change-password', (req, res, next) => {
	if(req.params.id !== req.user.id)
		return next(new Error())
	userFacade.scope(['password']).updateById(req.params.id, req.body).then( ... )
})
```

and it works the same for updates.


## Things you should know

* It works with deep nested objects too `my.deep.nested.value`
* all functionalities are kept from the facade you inherit from and even if you add you own functionalities they will still work (but there will be no scope applied yet)