Skip to content

Commit fd15a1a

Browse files
committed
feat: adds functional typescript api clone on NestJS
1 parent d665aa1 commit fd15a1a

26 files changed

+361
-22
lines changed

lesson_26/README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ We are continuing to build atop the foundation of our library app. For this assi
3636

3737
#### Running the API
3838

39-
You can run the server using the usual `./gradlew run` command. If you want to test that the server is running correctly, you can use `curl` like so:
39+
You can run the server using the usual `./gradlew run` command from the `api/java` directory. If you want to test that the server is running correctly, you can use `curl` like so:
4040

4141
```bash
4242
curl http://localhost:5000/items | json_pp
@@ -46,4 +46,8 @@ Alternatively, you can test the API using the tool [Postman][postman-link]. I re
4646

4747
## Additional resources
4848

49-
* [gRPC vs REST: Comparing API Styles in Practice (Article)](https://dev.to/anthonydmays/grpc-vs-rest-comparing-api-styles-in-practice-4bl): This article explains why the stuff most people call REST isn't actually.
49+
* [gRPC vs REST: Comparing API Styles in Practice (Article)](https://dev.to/anthonydmays/grpc-vs-rest-comparing-api-styles-in-practice-4bl): This article explains why the stuff most people call REST isn't actually.
50+
51+
[controller-file]: ./api/java/api_app/src/main/java/com/codedifferently/lesson26/web/MediaItemsController.java
52+
[controller-test-file]: ./api/java/api_app/src/test/java/com/codedifferently/lesson26/web/MediaItemsControllerTest.java
53+
[postman-link]: https://www.postman.com/downloads/

lesson_26/api/java/settings.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* in the user manual at https://docs.gradle.org/8.0.2/userguide/multi_project_builds.html
88
*/
99

10-
includeBuild("../../lib/java/codedifferently-instructional")
10+
includeBuild("../../../lib/java/codedifferently-instructional")
1111

1212
rootProject.name = "lesson_26"
1313
include("api_app")

lesson_26/api/javascript/api_app/src/app.module.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { Module } from '@nestjs/common';
22
import { AppController } from './app.controller';
33
import { AppService } from './app.service';
4+
import { WebModule } from './web/web.module';
45

56
@Module({
6-
imports: [],
7+
imports: [WebModule],
78
controllers: [AppController],
89
providers: [AppService],
910
})
Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
import { Module } from '@nestjs/common';
2+
import { LIBRARY_DATA_LOADER_PROVIDER } from './library_data_loader';
23
import { LibraryJsonDataLoader } from './library_json_data_loader';
34

45
@Module({
5-
providers: [LibraryJsonDataLoader],
6+
providers: [{
7+
provide: LIBRARY_DATA_LOADER_PROVIDER,
8+
useClass: LibraryJsonDataLoader
9+
}],
10+
exports: [LIBRARY_DATA_LOADER_PROVIDER]
611
})
712
export class DataModule {}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export { DataModule } from './data.module';
2-
export { LibraryDataLoader } from './library_data_loader';
2+
export { LIBRARY_DATA_LOADER_PROVIDER, LibraryDataLoader } from './library_data_loader';
3+

lesson_26/api/javascript/api_app/src/data/library_data_loader.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { LibraryDataModel } from '../models/library_data_model';
22

3-
export const LibraryDataLoaderSymbol = Symbol('LibraryDataLoader');
3+
export const LIBRARY_DATA_LOADER_PROVIDER = Symbol('LibraryDataLoader');
44

55
/** An object that loads data from a source and returns a LibraryDataModel object. */
66
export interface LibraryDataLoader {

lesson_26/api/javascript/api_app/src/data/library_json_data_loader.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Injectable } from "@nestjs/common";
2-
import { LibraryDataModel } from "src/models/library_data_model";
3-
import LibraryJsonData from '../../resources/data.json';
2+
import * as LibraryJsonData from '../../resources/data.json';
3+
import { LibraryDataModel } from "../models/library_data_model";
44
import { LibraryDataLoader } from "./library_data_loader";
55

66
@Injectable()

lesson_26/api/javascript/api_app/src/library/book.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,18 @@ export class Book extends MediaItemBase {
2929
return this.numberOfPages;
3030
}
3131

32+
protected matchesAuthor(authorQuery: string): boolean {
33+
if (!authorQuery) {
34+
return true;
35+
}
36+
for (const author of this.getAuthors()) {
37+
if (author.toLowerCase().includes(authorQuery.toLowerCase())) {
38+
return true;
39+
}
40+
}
41+
return false;
42+
}
43+
3244
toString(): string {
3345
return `Book{id='${this.getId()}', title='${this.getTitle()}'}`;
3446
}
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Module } from '@nestjs/common';
2-
import { LibraryDataLoader, LibraryDataLoaderSymbol } from '../data/library_data_loader';
2+
import { DataModule, LIBRARY_DATA_LOADER_PROVIDER, LibraryDataLoader } from '../data';
33
import { LibraryService } from './library.service';
44
import { LibraryFactory } from './library_factory';
55

@@ -8,10 +8,12 @@ const libraryServiceProvider = {
88
useFactory: (loader: LibraryDataLoader) => {
99
return LibraryFactory.createWithLoader(loader);
1010
},
11-
inject: [LibraryDataLoaderSymbol],
11+
inject: [LIBRARY_DATA_LOADER_PROVIDER],
1212
};
1313

1414
@Module({
15+
imports: [DataModule],
1516
providers: [libraryServiceProvider],
17+
exports: [LibraryService]
1618
})
1719
export class LibraryModule {}

lesson_26/api/javascript/api_app/src/library/library.service.ts

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
1+
import { Injectable, Logger } from '@nestjs/common';
12
import { Librarian } from './librarian';
23
import { LibraryGuest } from './library_guest';
34
import { MediaItem } from './media_item';
5+
import { CatalogSearcher } from './search/catalog_searcher';
6+
import { SearchCriteria } from './search/search_criteria';
47

8+
@Injectable()
59
export class LibraryService {
6-
private itemsById: Map<string, MediaItem> = new Map();
7-
private checkedOutItemIds: Set<string> = new Set();
8-
private checkedOutItemsByGuest: Map<string, Set<MediaItem>> = new Map();
9-
private guestsById: Map<string, LibraryGuest> = new Map();
10-
private id: string;
10+
private readonly itemsById: Map<string, MediaItem> = new Map();
11+
private readonly checkedOutItemIds: Set<string> = new Set();
12+
private readonly checkedOutItemsByGuest: Map<string, Set<MediaItem>> = new Map();
13+
private readonly guestsById: Map<string, LibraryGuest> = new Map();
14+
private readonly id: string;
15+
private readonly searcher: CatalogSearcher<MediaItem>;
16+
private readonly logger: Logger = new Logger(LibraryService.name);
1117

1218
constructor(id: string) {
1319
this.id = id;
20+
this.searcher = new CatalogSearcher(this.itemsById.values());
1421
}
1522

1623
getId(): string {
@@ -123,6 +130,16 @@ export class LibraryService {
123130
return this.checkedOutItemsByGuest.get(guest.getId()) || new Set();
124131
}
125132

133+
/**
134+
* Search the library for items matching the given query.
135+
*
136+
* @param query The query to search for.
137+
* @return The items matching the query.
138+
*/
139+
search(query: SearchCriteria): ReadonlySet<MediaItem> {
140+
return new Set(this.searcher.search(query));
141+
}
142+
126143
toString(): string {
127144
return `Library{itemsById=${Array.from(this.itemsById.entries())}, checkedOutItemIds=${Array.from(
128145
this.checkedOutItemIds

0 commit comments

Comments
 (0)