Skip to content

Commit

Permalink
add server docu
Browse files Browse the repository at this point in the history
  • Loading branch information
Metauriel committed Nov 17, 2023
1 parent 94535b8 commit 3c21cfe
Show file tree
Hide file tree
Showing 8 changed files with 418 additions and 170 deletions.
6 changes: 3 additions & 3 deletions docs/schulcloud-server/Coding-Guidelines/code-style.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,21 @@ The name of a function should clearly communicate what it does. There should be

There are a few keywords that we use with specific meaning:

#### is...
#### "is..."

`isTask()`, `isPublished()`, `isAuthenticated()`, `isValid()`

A function with the prefix "is..." is checking wether the input belongs to a certain (sub)class, or fulfils a specific criteria.

The function should return a boolean, and have no sideeffects.

#### check...
#### "check..."

`checkPermission()`, `checkInputIsValid()`

A function with the prefix "check..." is checking the condition described in its name, throwing an error if it does not apply.

#### has...
#### "has..."

`hasPermission()`,

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Domain Object Validation

If you need to validate a domain object, please write an independent class, so that the domain object itself, its repo and services can reuse it.

Eric Evans suggests using the specification pattern.
A specification fulfills the following interface:

```typescript
public interface Specification<T> {
boolean isSatisfiedBy(T t);
}
```

A specification checks if a domain object fulfills the conditions of the specification.

A specification can simply specify that a domain object is valid. E.g. a `Task` has an owner and a description.
A specification can specify more complex and specialized conditions. E.g. `Task` where every student assigned to the task's course has handed in a submission.

The specification pattern in its full extend describes how to use logic operators to combine multiple specifications into combined specifications as well. Please don't build this as long as you don't need it. YAGNI.
[More about full specification pattern](https://medium.com/@pawel_klimek/domain-driven-design-specification-pattern-82867540305c)
54 changes: 27 additions & 27 deletions docs/schulcloud-server/Coding-Guidelines/exception-handling.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
# Exception Handling

![](./img/exception-hierarchy.svg)
![exception hierarchy](./img/exception-hierarchy.svg)

We separate our business exceptions from technical exceptions. While for technical exceptions, we use the predefined HTTPExceptions from NestJS, business exceptions inherit from abstract BusinessException.

By default, implementations of BusinessException must define

```JSON
code: 500
type: "CUSTOM_ERROR_TYPE",
title: "Custom Error Type",
message: "Human readable details",
// additional: optionalData
code: 500
type: "CUSTOM_ERROR_TYPE",
title: "Custom Error Type",
message: "Human readable details",
// additional: optionalData
```

There is a GlobalErrorFilter provided to handle exceptions, which cares about the response format of exceptions and logging. It overrides the default NestJS APP_FILTER in the core/error-module.
Expand All @@ -36,7 +36,6 @@ try {
}
```


## Loggable exceptions

If you want the error log to contain more information than just the exception message, use or create an exception which implements the `Loggable` interface. Don't put data directly in the exception message!
Expand All @@ -47,28 +46,29 @@ See example below.

```TypeScript
export class UnauthorizedLoggableException extends UnauthorizedException implements Loggable {
constructor(private readonly username: string, private readonly systemId?: string) {
super();
}

getLogMessage(): ErrorLogMessage {
const message = {
type: 'UNAUTHORIZED_EXCEPTION',
stack: this.stack,
data: {
userName: this.username,
systemId: this.systemId,
},
};

return message;
}
constructor(private readonly username: string, private readonly systemId?: string) {
super();
}

getLogMessage(): ErrorLogMessage {
const message = {
type: 'UNAUTHORIZED_EXCEPTION',
stack: this.stack,
data: {
userName: this.username,
systemId: this.systemId,
},
};

return message;
}
}
```

```TypeScript
export class YourService {
public sampleServiceMethod(username, systemId) {
throw new UnauthorizedLoggableException(username, systemId);
}
public sampleServiceMethod(username, systemId) {
throw new UnauthorizedLoggableException(username, systemId);
}
}
```
```
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
33 changes: 16 additions & 17 deletions docs/schulcloud-server/Coding-Guidelines/logging.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,35 +8,34 @@ The message should be fixed in each loggable. If you want to log further data, p

```TypeScript
export class YourLoggable implements Loggable {
constructor(private readonly userId: EntityId) {}

getLogMessage(): LogMessage {
return {
message: 'I am a log message.',
data: { userId: this.userId, },
};
}
constructor(private readonly userId: EntityId) {}

getLogMessage(): LogMessage {
return {
message: 'I am a log message.',
data: { userId: this.userId, },
};
}
}

```

```TypeScript
import { Logger } from '@src/core/logger';

export class YourUc {
constructor(private logger: Logger) {
this.logger.setContext(YourUc.name);
}
constructor(private logger: Logger) {
this.logger.setContext(YourUc.name);
}

public sampleUcMethod(user) {
this.logger.log(new YourLoggable(userId: user.id));
}
public sampleUcMethod(user) {
this.logger.log(new YourLoggable(userId: user.id));
}
}
```

This produces a logging output like

```
```text
[NestWinston] Info - 2023-05-31 15:20:30.888 [YourUc] { message: 'I am a log message.', data: { userId: '0000d231816abba584714c9e' }}
```

Expand All @@ -46,4 +45,4 @@ The logger exposes the methods `log`, `warn`, `debug` and `verbose`. It does not

## Legacy logger

While transitioning to the new logger for loggables, the old logger for strings is still available as `LegacyLogger`.
While transitioning to the new logger for loggables, the old logger for strings is still available as `LegacyLogger`.
Loading

0 comments on commit 3c21cfe

Please sign in to comment.