Skip to content

Commit

Permalink
feat: otter sdk training - plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
sdo-1A committed Nov 27, 2024
1 parent 7020c59 commit b4280f7
Show file tree
Hide file tree
Showing 7 changed files with 206 additions and 6 deletions.
37 changes: 35 additions & 2 deletions apps/showcase/src/assets/trainings/sdk/program.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,40 @@
},
{
"stepTitle": "Customize your fetch client with plugins",
"htmlContentUrl": "./steps/plugins/instructions.md"
"htmlContentUrl": "./steps/plugins/instructions.md",
"filesConfiguration": {
"name": "plugins",
"startingFile": "apps/tutorial-app/src/app/app.config.ts",
"urls": [
{
"path": ".",
"contentUrl": "./shared/monorepo-template.json"
},
{
"path": "./libs/sdk",
"contentUrl": "@o3r-training/showcase-sdk/structure/spec.json"
},
{
"path": "./libs/sdk/src",
"contentUrl": "@o3r-training/showcase-sdk/structure/src.json"
},
{
"path": "./apps/tutorial-app/src/app",
"contentUrl": "./steps/plugins/exercise.json"
}
],
"solutionUrls": [
{
"path": "./apps/tutorial-app/src/app",
"contentUrl": "./steps/plugins/solution.json"
}
],
"mode": "interactive",
"commands": [
"npm install --legacy-peer-deps --ignore-scripts --force",
"npm run ng run tutorial-app:serve"
]
}
},
{
"stepTitle": "Integrate your SDK in Angular",
Expand Down Expand Up @@ -113,7 +146,7 @@
"urls": [
{
"path": ".",
"contentUrl": "./shared/monorepo-with-app.json"
"contentUrl": "./shared/monorepo-template.json"
},
{
"path": "./apps/app/src/app",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<table class="table">
<caption align="top">
First 10 pets with the status <b>available</b> from the Swagger Petstore
</caption>
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Name</th>
<th scope="col">Status</th>
</tr>
</thead>
<tbody>
@for (pet of pets(); track pet.id; let index = $index) {
<tr>
<td>{{ index + 1 }}</td>
<td>{{ pet.name }}</td>
<td>{{ pet.status }}</td>
</tr>
}
</tbody>
</table>
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Component, inject, signal } from '@angular/core';
import { type Pet, PetApi } from 'sdk';

@Component({
selector: 'app-root',
standalone: true,
imports: [],
templateUrl: './app.component.html',
styleUrl: './app.component.scss'
})
export class AppComponent {
/** Title of the application */
public title = 'tutorial-app';

private readonly petStoreApi = inject(PetApi);
private readonly petsWritable = signal<Pet[]>([]);
public readonly pets = this.petsWritable.asReadonly();

constructor() {
void this.setPets();
}

public async setPets() {
/* Get the first 10 pets whose status is 'available' */
const availablePets = await this.petStoreApi.findPetsByStatus({status: 'available'});
this.petsWritable.set(availablePets.slice(0, 10));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { ApiFetchClient } from '@ama-sdk/client-fetch';
import { PluginRunner, RequestOptions, RequestPlugin } from '@ama-sdk/core';
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
import { provideRouter } from '@angular/router';
import { Pet, PetApi } from 'sdk';
import { routes } from './app.routes';

class MockInterceptRequest implements RequestPlugin {
public load(): PluginRunner<RequestOptions, RequestOptions> {
return {
transform: async () => {
// TODO Create a mock response of type Pet[]
// TODO Store the stringified object in a Blob and create an object URL
// TODO Replace the original base path with the URL of the Blob
const basePath = '/target your blob resource/';

return {
method: 'GET',
headers: new Headers(),
basePath
}
}
};
}
}

// TODO Add your plugin to the Api Fetch Client
function petApiFactory() {
const apiFetchClient = new ApiFetchClient(
{
basePath: 'https://petstore3.swagger.io/api/v3',
requestPlugins: [],
replyPlugins: [],
fetchPlugins: []
}
);
return new PetApi(apiFetchClient);
}

export const appConfig: ApplicationConfig = {
providers: [
provideZoneChangeDetection({ eventCoalescing: true }),
provideRouter(routes),
{provide: PetApi, useFactory: petApiFactory}
]
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
Thanks to the `@ama-sdk/core` plugins, you can intercept the API requests and responses to transform their data or
perform actions such as authentication, logging, etc.

These plugins will be applied before sending all the API requests and after the reception of the responses.

### Objective
In this tutorial, you will configure the `PetApi` to create a plugin whose purpose is to intercept the request before it is sent and serve a mocked response instead.

### Pre-requisite
- The package `@ama-sdk/core` needs to be installed (which has already been done for you).

### Exercise
Create your own plugin that implements the `RequestPlugin` interface to mock the request plugin.
The exercise already contains the beginning of the code to inspire you. Here are some hints to help you as well:
- First, create a mock response of type `Pet[]` from the SDK.
- This object should be stringified and used to create a <a href="https://developer.mozilla.org/en-US/docs/Web/API/Blob" target="_blank">Blob</a>.
- Use the created `Blob` object to replace the base path (**hint**: check out the method <a href="https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL_static" target="_blank">URL.createObjectURL()</a>).

If implemented correctly, you should now see your mock response in the table of available pets, instead of the response from the Swagger Petstore.

> [!NOTE]
> Don't forget to check the exercise solution!
> [!TIP]
> The Otter framework provides several mock intercept plugins, including a mock intercept request plugin, which you can look further into if wanted to compare to this exercise.
> For more information, you can find all the <a href="https://github.com/AmadeusITGroup/otter/tree/main/packages/%40ama-sdk/core#available-plugins" target="_blank">project plugins</a>
> in the @ama-sdk/core package of the Otter framework.
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { ApiFetchClient } from '@ama-sdk/client-fetch';
import { PluginRunner, RequestOptions, RequestPlugin } from '@ama-sdk/core';
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
import { provideRouter } from '@angular/router';
import { Pet, PetApi } from 'sdk';
import { routes } from './app.routes';

class MockInterceptRequest implements RequestPlugin {
public load(): PluginRunner<RequestOptions, RequestOptions> {
return {
transform: async () => {
const mockData: Pet[] = [{ name : "mockPetName", photoUrls: ["mockPhotoUrl"], status: "available"}];
const text = JSON.stringify(mockData);
const blob = new Blob([text], { type: 'application/json' });
const basePath = URL.createObjectURL(blob);

return {
method: 'GET',
basePath,
headers: new Headers()
};
}
};
}
}

function petApiFactory() {
const apiFetchClient = new ApiFetchClient(
{
basePath: 'https://petstore3.swagger.io/api/v3',
requestPlugins: [new MockInterceptRequest()],
replyPlugins: [],
fetchPlugins: []
}
);
return new PetApi(apiFetchClient);
}

export const appConfig: ApplicationConfig = {
providers: [
provideZoneChangeDetection({ eventCoalescing: true }),
provideRouter(routes),
{provide: PetApi, useFactory: petApiFactory}
]
};
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,16 @@ export class AppComponent {
public title = 'tutorial-app';

private readonly petStoreApi = inject(PetApi);
readonly #pets = signal<Pet[]>([]);
public readonly pets = this.#pets.asReadonly();
private readonly petsWritable = signal<Pet[]>([]);
public readonly pets = this.petsWritable.asReadonly();

constructor() {
void this.setPets();
}

public async setPets() {
/* Get the first 10 pets whose status is 'available' */
const pets = await this.petStoreApi.findPetsByStatus({status: 'available'});
this.#pets.set(pets.slice(0, 10));
const availablePets = await this.petStoreApi.findPetsByStatus({status: 'available'});
this.petsWritable.set(availablePets.slice(0, 10));
}
}

0 comments on commit b4280f7

Please sign in to comment.