1 min read

Introduce a new route and custom contract

This article based on Poq.ApiTemplate.Node, it would be easier to understand if you set up you environment according to the guide: Your first BFC

In some cases a mobile application requires some specific data that is not part of the Poq contracts. Given examples will help you to understand when and how to deal with that.

Let's define when and how question to describe the use case:

Why do we need to add a new route?

That's depends on business requirements and it could happen in cases when:

  • Mobile client need to support some extra screens that don't exist OOB.
  • Mobile client need to support some contract that is not in a list of the Poq Contracts.

How to do that?

Let's assume your project is set up and ready for development, the ApiTemplate.Node is used to create the project.

Open your project in IDE and follow to ./src/modules folder.

# Folders tree
./src/modules
├── accounts
│   ├── controllers
│   └── dto
├── cart
│   ├── controllers
│   └── dto
├── checkout
│   └── controllers
...
├── search
│   ├── controllers
│   ├── dto
│   ├── mappers
│   └── services
├── shop
│   ├── controllers
│   └── services
├── stores
│   ├── controllers
│   ├── dto
│   └── services
├── system
│   ├── controllers
│   └── dto
├── voucher
│   ├── controllers
│   └── dto
└── wishlist
├── controllers
├── dto
└── services

This folders tree contains modules, to introuduce new router we would like to suggest using the same structure for you to add a new module and then controller. Let's for example add new superproduct route.

  1. Create a new folder in ./src/modules.

    # controllers folder contains all necessary controllers with route handlers
    # dto folder contains all necessary input/output models to be consumed by controllers
    # service folder contains all necessary service to work with 3td party data providers and etc.
    ./src/modules
    └── superproduct
    ├── contracts
    ├── controllers
    ├── dto
    └── services
    ...
  2. Add new controller to the folder (pay attention to a naming convention).

    ./src/modules
    └── superproduct
    ├── contracts
    │ ├── index.ts
    │ └── superproduct.ts
    ├── controllers
    │ ├── index.ts
    │ └── superproduct.controller.ts
    ├── dto
    ├── services
    │ ├── index.ts
    │ └── superproduct.service.ts
    ├── superproduct.module.ts
    └── index.ts
    ...
  3. Create a new contract superproduct.ts as:

    export class SuperProduct {
    readonly id: string;
    readonly name: string;
    readonly superProperty: string;
    readonly customData?: Record<string, unknown>;
    constructor(
    id: string,
    name: string,
    superProperty: string,
    customData?: Record<string, unknown>
    ) {
    ...
    }
    }
  4. Logic to deal with @poq/sdk or other 3rd party services and ORMs can be put in superproduct.service.ts as:

    @Injectable()
    export class SuperProductService {
    constructor(...) {
    ...
    }
    getSuperProductById(id: string): T {
    ...
    return new PoqResponse.from(HttpStatus.OK, new SuperProduct(
    id,
    name,
    superProperty,
    {
    // Custom data
    // Some custom properties
    }
    ));
    }
    }
  5. Then for the superproduct.controller.ts you can introduce a new handler for any path like:

    ...
    @Controller({ path: '/superproduct', scope: Scope.REQUEST })
    export class SuperProductController {
    constructor(private superProductService: SuperProductService) {}
    @Get('/id')
    async getSuperProduct(@Params('id') id: string): Promise<SuperProduct> {
    // Here we assume the service return
    const superProductResponse = await this.superProductService.getSuperProductById(id);
    if (superProductResponse.failure) {
    throw new HttpException(...);
    }
    return superProductResponse.content;
    }
    }
  6. Final step of development is to add superproduct.module.ts and import this module in ./src/app.module as:

    // superproduct.module.ts
    ...
    @Module({
    imports: [CoreModule, SdkSfccModule],
    controllers: [SuperProductController],
    providers: [SuperProductService]
    })
    export class SuperProductModule {}
    // app.module.ts
    ...
    @Module({
    imports: [
    ...,
    SuperProductModule
    ],
    ...
    })
    export class AppModule {}
  7. Run app after adding all the parts and check response via curl utlitiy or postman.

    curl --location --request GET 'http://localhost:3000/superproduct/qq2323mxr' \
    --header 'Host: poq-api-sfcc-node-demo-dev.azurewebsites.net' \
    --header 'poq-app-id: xxx' \
    --header 'poq-app-identifier: xxxxxxx-xxxxxx-xxxxxxx-xxxxxx' \
    --header 'authorization: Bearer xxx' \
    --header 'accept: */*' \
    --header 'poq-currency-identifier: USD' \
    --header 'version-code: 18.0' \
    --header 'accept-language: en-us' \
    --header 'platform: iphone' \
    --header 'poq-user-id: xxxxxx-xxxxxx-xxxxxx-xxxxxx' \
    --header 'currency-code: USD'
    # Response
    #
    # {
    # "id": "qq2323mxr",
    # "name": "Some SuperProduct",
    # "superProperty": "Property[X230183088889301-QQAZW-121]",
    # "customData": {
    # "customField1": true,
    # "customField": 2
    # }
    # }
  8. That's it. You added the new route, controller and the contract.