From c94ac40a7ae92833d2d652eb96770248a905a862 Mon Sep 17 00:00:00 2001 From: Stefan Date: Tue, 16 Jul 2024 08:21:39 -0400 Subject: [PATCH] adding language specifiers --- src/content/docs/architecture/backend.md | 28 +++++++++---------- src/content/docs/architecture/index.md | 2 +- .../state_management/event_transformers.md | 18 ++++++------ .../docs/testing/golden_file_testing.md | 2 +- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/content/docs/architecture/backend.md b/src/content/docs/architecture/backend.md index aab0f7a..6911aea 100644 --- a/src/content/docs/architecture/backend.md +++ b/src/content/docs/architecture/backend.md @@ -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/ @@ -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, @@ -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 create({ required String name, @@ -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 ``` @@ -137,7 +137,7 @@ 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 ``` @@ -145,7 +145,7 @@ my_api/v1/todos?completed=false 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() async => Map.from(jsonDecode(await body()) as Map); @@ -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()); ``` @@ -163,7 +163,7 @@ 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 ``` @@ -171,7 +171,7 @@ PATCH my_api/v1/todos/1 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 ``` @@ -179,7 +179,7 @@ DELETE my_api/v1/todos/1 //Data source should only require the ID 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().get(id); if (todo == null) { @@ -187,7 +187,7 @@ if (todo == null) { } ``` -``` +```dart late final requestBody; try { requestBody = CreateTodoRequest.fromJson(jsonDecode(await context.request.body() as Map)); @@ -197,7 +197,7 @@ try { ``` -``` +```dart try { await someServerSideProcess(); } catch (e) { diff --git a/src/content/docs/architecture/index.md b/src/content/docs/architecture/index.md index 18bd622..6dce625 100644 --- a/src/content/docs/architecture/index.md +++ b/src/content/docs/architecture/index.md @@ -53,7 +53,7 @@ The presentation layer and state management live in the project's `lib` folder. Good ✅ -``` +```txt my_app/ |- lib/ | |- login/ diff --git a/src/content/docs/state_management/event_transformers.md b/src/content/docs/state_management/event_transformers.md index 51b9e7f..4169fe4 100644 --- a/src/content/docs/state_management/event_transformers.md +++ b/src/content/docs/state_management/event_transformers.md @@ -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 { MyBloc() : super(MyState()) { on( @@ -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 { MyBloc() : super(MyState()) { on( @@ -58,7 +58,7 @@ class MyBloc extends Bloc { 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 { MoneyBloc() : super(MoneyState()) { on(_onChangeBalance, transformer: concurrent()); @@ -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 { SayHiBloc() : super(SayHiState()) { on( @@ -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 { ThoughtBloc() : super(ThoughtState()) { on( @@ -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( '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), @@ -152,14 +152,14 @@ blocTest( 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.delayed(Duration.zero)` statement in the `act` function will ensure that the task queue is empty before additional events are added: -``` +```dart blocTest( 'change value', build: () => MyBloc(), act: (bloc) { bloc.add(ChangeValue(add: 1)); await Future.delayed(Duration.zero); - bloc.add(ChangeValue(remove: 1); + bloc.add(ChangeValue(remove: 1)); }, expect: () => const [ MyState(value: 1), diff --git a/src/content/docs/testing/golden_file_testing.md b/src/content/docs/testing/golden_file_testing.md index 5e40f0e..c53a0df 100644 --- a/src/content/docs/testing/golden_file_testing.md +++ b/src/content/docs/testing/golden_file_testing.md @@ -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."