BingoMeetings–4 steps to run in Docker both WebAPI and Site-part 22

Bingo

Bingo is a small project, written in TypeScript , and developed with Alexandru Badita in launch break (one hour - more or less). You can find sources at https://github.com/alexandru360/PresentationBingoCards/ . Those are my blog posts for Bingo : ( scroll below for the post)
NrLink
1Create meeting
2Create Tests
3Finalize Create meeting
4Sharing meeting
5Keep Score
6Add obsolete
7Finalizing obsolete
8End meeting
9Dockerize tests
10Azure CI tests
11Yarn workspaces
12CLI
13Intermezzo - CLI improvements
14typescript compile run with node
15NestJS ,swagger and create a meeting
16Finalizing API
17Intermezzo - jest vs jasmine error
18Refactor WebAPI and test service
19Heroku Deploy NestJs
20Angular
21Deploy Angular to GitHub
22WebAPI and Web
23Documentation
24Documentation of the code
25Conclusions

Now what I want to achieve is to run the WebAPI and Angular Site in docker. For this, we should compile the Angular site and copy into the WebAPI. Also, WebAPI should serve the index.html file generated by the Angular.

Those are the 4 steps:

1. Ensure that  the Angular routes and WebAPI routes should be different Solution: this is easy achieved by having /api prepended to the WebAPI routes)

2. The WebAPI should be configured as to build to different configurations: for our purpose, calling  root ( /). For docs ( https://alexandru360.github.io/PresentationBingoCards/ ) it should call official deploy http://bingo-meeting-api.herokuapp.com/api/ 

Solution: read about environment https://angular.io/guide/build . I have made a new environment dockerbuild  Rememeber to create a new environment.ts  + a new entry in angular.json to build this configuration + an entry in package.json to build it . Then modify the service to use environment( see the modifications at https://github.com/alexandru360/PresentationBingoCards/commit/6dafb0c0b005d46bc426d128f9caf5d53e039dfa ).

3. For NestJs to serve html file , add nest-middlewares/serve-static  , then add the following code in the appropiate places:

ServeStaticModule

.forRoot({

rootPath: join(__dirname, ‘..’, ‘dist’,’bingo-cards-ui’),

})],

ServeStaticMiddleware.configure(‘/test’ );

consumer.apply(ServeStaticMiddleware).forRoutes(‘/test’);

( see https://github.com/alexandru360/PresentationBingoCards/commit/6dafb0c0b005d46bc426d128f9caf5d53e039dfa )

4. In the docker compile the Angular , then copy the files into WebAPI folder, then run the WebAPI site . See https://github.com/alexandru360/PresentationBingoCards/blob/master/dockerize/docker_runwebapiweb.txt and https://github.com/alexandru360/PresentationBingoCards/blob/master/dockerize/build_RunWebApiWeb.bat

BingoMeetings–build and deploy Angular WebSite to GitHub–part 21

Bingo

Bingo is a small project, written in TypeScript , and developed with Alexandru Badita in launch break (one hour - more or less). You can find sources at https://github.com/alexandru360/PresentationBingoCards/ . Those are my blog posts for Bingo : ( scroll below for the post)
NrLink
1Create meeting
2Create Tests
3Finalize Create meeting
4Sharing meeting
5Keep Score
6Add obsolete
7Finalizing obsolete
8End meeting
9Dockerize tests
10Azure CI tests
11Yarn workspaces
12CLI
13Intermezzo - CLI improvements
14typescript compile run with node
15NestJS ,swagger and create a meeting
16Finalizing API
17Intermezzo - jest vs jasmine error
18Refactor WebAPI and test service
19Heroku Deploy NestJs
20Angular
21Deploy Angular to GitHub
22WebAPI and Web
23Documentation
24Documentation of the code
25Conclusions

What  we need is to deploy somewhere the WebSite application – the Angular. One version is to compile and deploy to the WebApi (http://bingo-meeting-api.herokuapp.com/api/ ), however  , I do prefer keeping separate.

One simple idea is to deploy to GitHub site . For each repository , GitHub lets you have a website correlated . For example , for our project, https://github.com/alexandru360/PresentationBingoCards/ , github lets you have the site https://alexandru360.github.io/PresentationBingoCards/ ( see username and repository changing position?) . What is there could come form different GitHub project settings – I choose to be in the docs folder.

So we need to compile the Angular Application and put the result on the docs folder on  Github

If we do this on a CI on Azure, it could provide an endless loop ( push code oin GitHub, compoiling on Azure, push on GitHub folder docs, compile again…)

So it should come from Developer PC. But how to do this in a repeatable manner ? Simple – Docker!

So we build inside Docker the Angular site, copy the compile from Docker on the local system, then we manually push the modifications on Github. The system has the advantage that it can be reproducible also on Azure.

So the bat looks like this

call build_web.bat
del /S /Q ..\docs\*.*
copy dist\bingo-cards-ui\*.* ..\docs\

See https://github.com/alexandru360/PresentationBingoCards/tree/master/docs  for more details about the docker files.

One small modification also: the base href from angular should be this, to accept https://alexandru360.github.io/PresentationBingoCards/ that is not rooted:

<!– <base href=”/”> –>

<script>

var isCordovaApp = !!window.cordova;

var hrefApp = “.”;

if (!isCordovaApp) {

var baseHref = window.location.href.split(‘/’);

baseHref.pop();

hrefApp = baseHref.join(‘/’) + ‘/’;

}

document.write(‘<base href=”‘ + hrefApp + ‘” />’);

</script>

create docker to deploy to docs

build_docs.bat

Bingo for meetings-build an Angular app-part 20

Bingo

Bingo is a small project, written in TypeScript , and developed with Alexandru Badita in launch break (one hour - more or less). You can find sources at https://github.com/alexandru360/PresentationBingoCards/ . Those are my blog posts for Bingo : ( scroll below for the post)
NrLink
1Create meeting
2Create Tests
3Finalize Create meeting
4Sharing meeting
5Keep Score
6Add obsolete
7Finalizing obsolete
8End meeting
9Dockerize tests
10Azure CI tests
11Yarn workspaces
12CLI
13Intermezzo - CLI improvements
14typescript compile run with node
15NestJS ,swagger and create a meeting
16Finalizing API
17Intermezzo - jest vs jasmine error
18Refactor WebAPI and test service
19Heroku Deploy NestJs
20Angular
21Deploy Angular to GitHub
22WebAPI and Web
23Documentation
24Documentation of the code
25Conclusions

Now it is time to create some Angular GUI. ( If you want to learn Angular, please visit https://angular.io/ )

Problems encountered:

1. The CreateMeeting did not compile (ng serve ) the CreateMeeting class ( because of the nestjs Swagger  decorators ).

export class CreateMeeting  {
  @ApiModelProperty()
  userName: string;
  @ApiModelProperty()
  meetingName: string;
}

So I ended creating an interface ICreateMeeting with the same definition

export interface ICreateMeeting{
    userName: string;
    meetingName: string;
}
export class CreateMeeting implements ICreateMeeting {
  @ApiModelProperty()
  userName: string;
  @ApiModelProperty()
  meetingName: string;
}

and using in ReactiveForms as

 const c: ICreateMeeting = {userName: '', meetingName: ''};
 this.createMeetingForm = this.formBuilder.group(c);

Also, because the interface have the same signature as the class, we can use to POST data

public SaveMeeting(create: ICreateMeeting): Observable<Meeting> {
    const url: string = this.urlApi + 'meetings';
    return this.httpAPI.post<Meeting>(url, create);
  }

2. We should call WebAPI as http if the site is http and https if the site is https.  The problem is that the URL is hardCoded

private urlApi = 'http://bingo-meeting-api.herokuapp.com/';

We can have to inject the document to obtain the  doc.location.protocol

  constructor(@Inject(DOCUMENT)private doc: Document,  private httpAPI: HttpClient) {
     this.protocol = doc.location.protocol;
  }

but we remember there is a better way with // , that means respecting the protocol

  private urlApi = '//bingo-meeting-api.herokuapp.com/';

 

3. TypeScript – ng build works, but ng build –prod –build-optimizer gives an obscure error.
The solving was to add in the tsconfig.json
“noUnusedLocals”: true,
“noUnusedParameters”: false,

and solve unused declarations.

You can find the results at https://alexandru360.github.io/PresentationBingoCards/

Bingo meetings–deploying to heroku–part 19

Bingo

Bingo is a small project, written in TypeScript , and developed with Alexandru Badita in launch break (one hour - more or less). You can find sources at https://github.com/alexandru360/PresentationBingoCards/ . Those are my blog posts for Bingo : ( scroll below for the post)
NrLink
1Create meeting
2Create Tests
3Finalize Create meeting
4Sharing meeting
5Keep Score
6Add obsolete
7Finalizing obsolete
8End meeting
9Dockerize tests
10Azure CI tests
11Yarn workspaces
12CLI
13Intermezzo - CLI improvements
14typescript compile run with node
15NestJS ,swagger and create a meeting
16Finalizing API
17Intermezzo - jest vs jasmine error
18Refactor WebAPI and test service
19Heroku Deploy NestJs
20Angular
21Deploy Angular to GitHub
22WebAPI and Web
23Documentation
24Documentation of the code
25Conclusions

We have decided to deploy on heroku, since it has some free dynos. Heroku is integrated with GitHub and has “automatic deploys” – that means that every push will automatically deploy to Heroku. That will be an opportunity for AzureDevOps to verify correct deploy ( even if appears different …)

Some points here:

1. Heroku is calling web npm start . So  in the root of the project we should have a package.json with a start script that starts our api

“start”: “cd bingo-cards-api && yarn start”,

2. Heroku is stripping dev dependecies. So, if you did not compile the project – and want too use tsc or other dependemcies, you should add on Heroku site the setting  NPM_CO NFIG_PRODUCTION false

3. The swagger from nestjs is , somehow, calling the HTTP, not the HTTPS . So the https://bingo-meeting-api.herokuapp.com/api/ does not work, but http://bingo-meeting-api.herokuapp.com/api/ works

4.Because we can call from other sites, the CORS should be enabled .

app.enableCors();

5. Also , we should enable dynamic port for Heroku

const port: string = process.env.PORT || “3000”;
await app.listen(parseInt(port, 10));

 

After this, you can try the API at http://bingo-meeting-api.herokuapp.com/api/

Bingo for–refactor web service with tests–part 18

Bingo

Bingo is a small project, written in TypeScript , and developed with Alexandru Badita in launch break (one hour - more or less). You can find sources at https://github.com/alexandru360/PresentationBingoCards/ . Those are my blog posts for Bingo : ( scroll below for the post)
NrLink
1Create meeting
2Create Tests
3Finalize Create meeting
4Sharing meeting
5Keep Score
6Add obsolete
7Finalizing obsolete
8End meeting
9Dockerize tests
10Azure CI tests
11Yarn workspaces
12CLI
13Intermezzo - CLI improvements
14typescript compile run with node
15NestJS ,swagger and create a meeting
16Finalizing API
17Intermezzo - jest vs jasmine error
18Refactor WebAPI and test service
19Heroku Deploy NestJs
20Angular
21Deploy Angular to GitHub
22WebAPI and Web
23Documentation
24Documentation of the code
25Conclusions

In the same manner that we refactor the objects, we have now to refactor the service that is called by the WebAPI. Yes, we have the skinny controllers concept – but the service is something new for the application. Think about retrieving the list of the meetings  – this is something that we did not need in the console application( it was just the current meeting)

So how to test ? The easy way is to put the service ( with the dependencies) in a new project –  bingo-cards-api-objects. Then reference the project from bingo-cards-api nestjs webAPI – and ensure it works. Now it is the time for tests:

describe("Meetings API service creation", () => {
    it("a meeting should have been created properly ", async () => {
        const ms: MeetingService =new MeetingService();
        const userName:string = "Andrei";
        const meetingName:string = "Meeting today"
        const m:Meeting =await  ms.create(userName,meetingName);
        expect(m.Name).toBe(meetingName);
        expect(m.Participants.length).toBe(1);
        expect(m.Participants[0].Name).toBe(userName);
      });
      it("a meeting should have been retrieved properly ", async () => {
        const ms: MeetingService =new MeetingService();
        const userName:string = "Andrei";
        const meetingName:string = "Meeting today"
        const m :Meeting=await  ms.create(userName,meetingName);
        const retr :ActualMeeting[]= ms.ActualMeetings();

        expect(retr.length).toBe(1);

        expect(retr[0].idMeeting).toBe(m.Id);
        expect(retr[0].participantName).toBe(userName);

      });
  });

And that is not all. As the code for checkCard look , it should be more tests….

public checkCard(idMeeting: any, idCard: number, nameParticipant: string ): Meeting{
        const m = this.meetings.find(it => it.Id === idMeeting );
        // TODO: throw if meeting is null
        const c = m.FindCard(idCard);
        // TODO: throw if card is null
        const p = m.FindParticipantAfterName(nameParticipant);
        // TODO: throw if participant is null

        m.CheckCardByParticipant(c, p);
        return m;

    }

Not that I have time for this…

Intermezzo – NestJS + Jest vs Angular + Jasmine

Bingo

Bingo is a small project, written in TypeScript , and developed with Alexandru Badita in launch break (one hour - more or less). You can find sources at https://github.com/alexandru360/PresentationBingoCards/ . Those are my blog posts for Bingo : ( scroll below for the post)
NrLink
1Create meeting
2Create Tests
3Finalize Create meeting
4Sharing meeting
5Keep Score
6Add obsolete
7Finalizing obsolete
8End meeting
9Dockerize tests
10Azure CI tests
11Yarn workspaces
12CLI
13Intermezzo - CLI improvements
14typescript compile run with node
15NestJS ,swagger and create a meeting
16Finalizing API
17Intermezzo - jest vs jasmine error
18Refactor WebAPI and test service
19Heroku Deploy NestJs
20Angular
21Deploy Angular to GitHub
22WebAPI and Web
23Documentation
24Documentation of the code
25Conclusions

We decided to add an Angular project.  As a immediate consequence , the compile ( tsc ) of the API ( bingo-cards-api) it failes with the first error being:

../node_modules/@types/jasmine/ts3.1/index.d.ts:16:1 – error TS6200: Definitions of the following identifiers conflict with those in another file: beforeAll, beforeEach, afterAll, afterEach, describe, fdescribe, xdescribe, it, fit, xit, expect, DEFAULT_TIMEOUT_INTERVAL, CustomMatcherFactory, CustomEqualityTester

 

Obviously, we have a conflict… And the conflict is done by Angular( that comes with Jasmine by default) and Nest ( that comes with Jest) ( and us, that we have choose Jest)

 

There are 3 solving paths:

  1. Convert all to Jasmine
  2. Convert all to Jest
  3. Eliminate the tests from the Angular , eliminate the tests from Nest and create the own library to test (we have done already this, in bingo-meeting-objects-test)

 

Solution 1 : means re-factor all. Not good.

I have tried the 2 , but , in spite of many tutorials on the internet, some problems have arrived.

So we have the 3 : eliminate all references to Jest and Jasmine, with the exception of bingo-meeting-objects-test

And… it worked!

 

Bingo for meetings–finalizing API for web–part 16

Bingo

Bingo is a small project, written in TypeScript , and developed with Alexandru Badita in launch break (one hour - more or less). You can find sources at https://github.com/alexandru360/PresentationBingoCards/ . Those are my blog posts for Bingo : ( scroll below for the post)
NrLink
1Create meeting
2Create Tests
3Finalize Create meeting
4Sharing meeting
5Keep Score
6Add obsolete
7Finalizing obsolete
8End meeting
9Dockerize tests
10Azure CI tests
11Yarn workspaces
12CLI
13Intermezzo - CLI improvements
14typescript compile run with node
15NestJS ,swagger and create a meeting
16Finalizing API
17Intermezzo - jest vs jasmine error
18Refactor WebAPI and test service
19Heroku Deploy NestJs
20Angular
21Deploy Angular to GitHub
22WebAPI and Web
23Documentation
24Documentation of the code
25Conclusions

The API that we want to create is

  1. create meeting
  2. add participant
  3. check cards
  4. see result meeting(

Those API’s  were simpler for the console application, because of the single participant involved.

There are also some technical problems and some architectural ones.

Let’s start with technical: nestjs suggest ( as per sample project with contacts) to add a route like:

    @Put(':id/addParticipant')
    async addParticipant(@Param('id') id: any, @Body() nameParticipant: string): Promise<Meeting> {
        // console.log(`userName : ${JSON.stringify(cm.userName)}  meetingName: ${JSON.stringify(cm.meetingName)}`);
        return this.meetingsService.AddParticipant(id, nameParticipant);
    }

However , this is not available to be tested via Swagger – so we modify to

export class AddParticipant {
    @ApiModelProperty()
  meetingId: any;
  @ApiModelProperty()
  nameParticipant: string;
}
//CODE OF THE CONTROLLER OMITTED
@Put('addParticipant')
    async addParticipant(@Body() addParticipant: AddParticipant): Promise<Meeting> {
        // console.log(`userName : ${JSON.stringify(cm.userName)}  meetingName: ${JSON.stringify(cm.meetingName)}`);
        return this.meetingsService.AddParticipant(addParticipant.meetingId, addParticipant.nameParticipant);
    }


Also, when we handle in the meeting service the CheckCard we discover to be missing something for the original DDD model . For example, we need a FindCard and FindParticipantAfterName .

public checkCard(idMeeting: any, idCard: number, nameParticipant:string ): Meeting{
        const m = this.meetings.find(it => it.Id === idMeeting );
        // TODO: throw if meeting is null
        const c = m.FindCard(idCard);
        // TODO: throw if card is null
        const p = m.FindParticipantAfterName(nameParticipant);
        // TODO: throw if participant is null

        m.CheckCardByParticipant(c, p);
        return m;

    }

For the architectural ones:

  1. The service that we just created should be tested and put into the right project. It could belong to the bingo-meeting-objects.
  2. The controller has some classes that should be tested. However, the classes involving in the @Body have   swagger attributes, so they cannot be moved into bingo-meeting-objects .
export class AddParticipant {
//bingo-meeting-objects  should not have reference to swagger properties
    @ApiModelProperty()
  meetingId: any;
  @ApiModelProperty()
  nameParticipant: string;
}


Download the actual code from https://github.com/alexandru360/PresentationBingoCards/releases/tag/api_final

Bingo for meetings-nestjs–create meeting api -part 15

Bingo

Bingo is a small project, written in TypeScript , and developed with Alexandru Badita in launch break (one hour - more or less). You can find sources at https://github.com/alexandru360/PresentationBingoCards/ . Those are my blog posts for Bingo : ( scroll below for the post)
NrLink
1Create meeting
2Create Tests
3Finalize Create meeting
4Sharing meeting
5Keep Score
6Add obsolete
7Finalizing obsolete
8End meeting
9Dockerize tests
10Azure CI tests
11Yarn workspaces
12CLI
13Intermezzo - CLI improvements
14typescript compile run with node
15NestJS ,swagger and create a meeting
16Finalizing API
17Intermezzo - jest vs jasmine error
18Refactor WebAPI and test service
19Heroku Deploy NestJs
20Angular
21Deploy Angular to GitHub
22WebAPI and Web
23Documentation
24Documentation of the code
25Conclusions

So now it is time to expose our objects as HTTP API. We have decided to go with nest.js because has support for TypeScript. The documentation to install is pretty obvious at https://docs.nestjs.com/ .

Now we must code the endpoint to create a meeting. As per the nest.js documentation , we should create a module ,a controller and a service to redirect calls . The problem is that , to create a meeting, we should transmit 2 parameters: userName and meetingName. To do this via  HTTP, we must create a new class with this 2 parameters :


export class CreateMeeting {
  readonly userName: string;
  readonly meetingName: string;
}

Also we want to add Swagger as show at https://docs.nestjs.com/recipes/swagger .  And for this, according to the documentation , we should decorate the class:

import { ApiModelProperty } from '@nestjs/swagger';

export class CreateMeeting {
  @ApiModelProperty()
  readonly userName: string;
  @ApiModelProperty()
  readonly meetingName: string;
}

And now we have a controller with 2 functions – get – to show all meetings – and post-  to create the meeting:

@Controller('meetings')
export class MeetingsController {
    constructor(private meetingsService: MeetingService){}

    @Get()
    index(): Meeting[] {
      return this.meetingsService.meetings;
    }

    @Post()
    async create(@Body() cm: CreateMeeting): Promise<Meeting> {
        console.log(`userName : ${JSON.stringify(cm.userName)}  meetingName: ${JSON.stringify(cm.meetingName)}`);
        return this.meetingsService.create(cm.userName, cm.meetingName);

    }
}

And now we have a fully qualified web api that can create a meeting.  And we have swagger to test functions.

That’s good for a start…

Andrei Ignat weekly software news(mostly .NET)

* indicates required

Please select all the ways you would like to hear from me:

You can unsubscribe at any time by clicking the link in the footer of our emails. For information about our privacy practices, please visit our website.

We use Mailchimp as our marketing platform. By clicking below to subscribe, you acknowledge that your information will be transferred to Mailchimp for processing. Learn more about Mailchimp's privacy practices here.