Skip to content

Commit

Permalink
Merge pull request #24 from VGVentures/fix/syntax_highlighting
Browse files Browse the repository at this point in the history
fix: syntax highlighting
  • Loading branch information
verygoodstefan authored Jul 16, 2024
2 parents 74bce07 + c94ac40 commit 2bb53bb
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 25 deletions.
28 changes: 14 additions & 14 deletions src/content/docs/architecture/backend.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Putting the backend in the same repository as the frontend allows developers to
While providers, routes, and tests, can live in the root backend project, consider putting data models and data access into their own dedicated package(s). Ideally, these layers should be able to exist independently from the rest of the app.


```
```txt
my_app/
|- api/
| |- lib/
Expand Down Expand Up @@ -68,7 +68,7 @@ my_app/

A `models` package should clearly define the necessary data models that the backend will be sharing with the frontend. Defining endpoint models makes the data necessary to communicate between frontend and backend more explicit. It also creates a data structure that can communicate additional metadata about content received, such as the total count of items and pagination information.

```
```dart
final class GetTodosResponse {
const GetTodosResponse({
int count = 0,
Expand All @@ -91,7 +91,7 @@ A data source package should allow developers to fetch data from different sourc

The best way to achieve this is by making an abstract data source with the necessary CRUD methods, and implementing this data source as needed based on where the data is coming from.

```
```dart
abstract class TodosDataSource {
Future<Todo> create({
required String name,
Expand All @@ -116,19 +116,19 @@ Routes should follow common [best practices for REST API design](https://swagger
Endpoints should be named for the collection of objects that they provide access to. Use plural nouns to specify the collection, not the individual entity.


```
```txt
my_api/v1/todos
```

Nested paths then provide specific data about an individual object within the collection.

```
```txt
my_api/v1/todos/1
```

When setting up a collection of objects that is nested under another collection, the endpoint path should reflect the relationship.

```
```txt
my_api/v1/users/123/todos
```

Expand All @@ -137,15 +137,15 @@ my_api/v1/users/123/todos

Query parameters serve as the standard way of filtering the results of a GET request.

```
```txt
my_api/v1/todos?completed=false
```

#### Map the Request Body of POST, PUT, and PATCH Requests

On requests to the server to create or update items, endpoints should take a stringified JSON body and decode it into a map so that the appropriate entity in the data source is changed. Since this is a common process for all create/update requests, consider adding a utility to map the request body.

```
```dart
extension RequestBodyDecoder on Request {
Future<Map<String, dynamic>> map() async =>
Map<String, dynamic>.from(jsonDecode(await body()) as Map);
Expand All @@ -154,7 +154,7 @@ extension RequestBodyDecoder on Request {

The request body can then be converted into the correct data model like in the endpoint code.

```
```dart
final body = CreateTodoRequest.fromJson(await context.request.map());
```

Expand All @@ -163,31 +163,31 @@ final body = CreateTodoRequest.fromJson(await context.request.map());
For update requests, PATCH is more advisable than PUT because [PATCH requests the server to update an existing entity, while PUT requests the entity to be replaced](https://stackoverflow.com/questions/21660791/what-is-the-main-difference-between-patch-and-put-request?answertab=oldest#tab-top).


```
```txt
PATCH my_api/v1/todos/1
```

#### DELETE should only require an identifier

DELETE requests should require nothing more than an identifier of the object to be deleted. There is no need to send the entire object.

```
```txt
DELETE my_api/v1/todos/1 //Data source should only require the ID
```

#### Return Appropriate Status Codes

Routes should also return proper status codes to the frontend based on the results of their operations. When an error occurs, sending a useful status and response to the client makes it clear what happened and allows the client to handle errors more smoothly.

```
```dart
final todo = context.read<TodosDataSource>().get(id);
if (todo == null) {
return Response(statusCode: HttpStatus.notFound, body: 'No todo exists with the given $id');
}
```

```
```dart
late final requestBody;
try {
requestBody = CreateTodoRequest.fromJson(jsonDecode(await context.request.body() as Map));
Expand All @@ -197,7 +197,7 @@ try {
```

```
```dart
try {
await someServerSideProcess();
} catch (e) {
Expand Down
2 changes: 1 addition & 1 deletion src/content/docs/architecture/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ The presentation layer and state management live in the project's `lib` folder.

Good ✅

```
```txt
my_app/
|- lib/
| |- login/
Expand Down
18 changes: 9 additions & 9 deletions src/content/docs/state_management/event_transformers.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ In particular, [race conditions](https://en.wikipedia.org/wiki/Race_condition) c
#### Registering Event Transformers
Event transformers are specified in the `transformer` field of the event registration functions in the `Bloc` constructor:

```
```dart
class MyBloc extends Bloc<MyEvent, MyState> {
MyBloc() : super(MyState()) {
on<MyEvent>(
Expand Down Expand Up @@ -45,7 +45,7 @@ Let's investigate the `sequential`, `droppable`, and `restartable` transformers

#### Sequential
The `sequential` transformer ensures that events are handled one at a time, in a first in, first out order from when they are received.
```
```dart
class MyBloc extends Bloc<MyEvent, MyState> {
MyBloc() : super(MyState()) {
on<MyEvent>(
Expand All @@ -58,7 +58,7 @@ class MyBloc extends Bloc<MyEvent, MyState> {

To illustrate the utility of sequential event handling, suppose we're building a money-tracking app. The `_onChangeBalance` handler first calls an API to read our current account balance, and then sends a call to update the balance to its new value:

```
```dart
class MoneyBloc extends Bloc<MoneyEvent, MoneyState> {
MoneyBloc() : super(MoneyState()) {
on<ChangeBalance>(_onChangeBalance, transformer: concurrent());
Expand Down Expand Up @@ -86,7 +86,7 @@ Note that when operations are safe to execute concurrently, using a `sequential`

#### Droppable
The `droppable` transformer will discard any events that are added while an event in that bucket is already being processed.
```
```dart
class SayHiBloc extends Bloc<SayHiEvent, SayHiState> {
SayHiBloc() : super(SayHiState()) {
on<SayHello>(
Expand All @@ -109,7 +109,7 @@ Since events added during ongoing handling will be discarded by the `droppable`

#### Restartable
The `restartable` transformer inverts the behavior of `droppable`, halting execution of previous event handlers in order to process the most recently received event.
```
```dart
class ThoughtBloc extends Bloc<ThoughtEvent, ThoughtState> {
ThoughtBloc() : super(ThoughtState()) {
on<ThoughtEvent>(
Expand All @@ -135,13 +135,13 @@ If we want to avoid emitting the declaration that `${event.thought}` is my most

#### Testing Blocs
When writing tests for a bloc, you may encounter an issue where a variable event handling order is acceptable in use, but the inconsistent sequence of event execution makes the determined order of states required by `blocTest`'s `expect` field results in unpredictable test behavior:
```
```dart
blocTest<MyBloc, MyState>(
'change value',
build: () => MyBloc(),
act: (bloc) {
bloc.add(ChangeValue(add: 1));
bloc.add(ChangeValue(remove: 1);
bloc.add(ChangeValue(remove: 1));
},
expect: () => const [
MyState(value: 1),
Expand All @@ -152,14 +152,14 @@ blocTest<MyBloc, MyState>(
If the `ChangeValue(remove: 1)` event completes execution before `ChangeValue(add: 1)` has finished, the resultant states will instead be `MyState(value: -1),MyState(value: 0)`, causing the test to fail.

Utilizing a `await Future<void>.delayed(Duration.zero)` statement in the `act` function will ensure that the task queue is empty before additional events are added:
```
```dart
blocTest<MyBloc, MyState>(
'change value',
build: () => MyBloc(),
act: (bloc) {
bloc.add(ChangeValue(add: 1));
await Future<void>.delayed(Duration.zero);
bloc.add(ChangeValue(remove: 1);
bloc.add(ChangeValue(remove: 1));
},
expect: () => const [
MyState(value: 1),
Expand Down
2 changes: 1 addition & 1 deletion src/content/docs/testing/golden_file_testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Good ✅

To configure a golden test tag across multiple files (or an entire package), create a `dart_test.yaml` file and add the tag configuration:

```
```yaml
tags:
golden:
description: "Tests that compare golden files."
Expand Down

0 comments on commit 2bb53bb

Please sign in to comment.