Skip to content

Commit 14a6a08

Browse files
feat(DTFS2-7052): new module geospatial
1 parent 2cdd0de commit 14a6a08

File tree

5 files changed

+137
-0
lines changed

5 files changed

+137
-0
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { ApiProperty } from '@nestjs/swagger';
2+
import { Matches, MaxLength, MinLength } from 'class-validator';
3+
4+
const UK_POSTCODE = /^[A-Za-z]{1,2}[0-9Rr][0-9A-Za-z]?\s?[0-9][ABD-HJLNP-UW-Zabd-hjlnp-uw-z]{2}$/;
5+
6+
export class GetAddressByPostcodeQueryDto {
7+
@ApiProperty({
8+
example: 'SW1A 2AQ',
9+
description: 'Postcode to search for',
10+
})
11+
@MinLength(5)
12+
@MaxLength(8)
13+
@Matches(UK_POSTCODE)
14+
public postcode: string;
15+
}
16+
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { ApiProperty } from '@nestjs/swagger';
2+
3+
export type GetSearchAddressesResponse = GetSearchAddressesResponseItem[];
4+
5+
export class GetSearchAddressesResponseItem {
6+
@ApiProperty({
7+
description: 'Organisation name if available',
8+
example: 'CHURCHILL MUSEUM & CABINET WAR ROOMS',
9+
})
10+
readonly organisationName: string | null;
11+
12+
@ApiProperty({
13+
description: 'Address line 1',
14+
example: 'CLIVE STEPS KING CHARLES STREET',
15+
})
16+
readonly addressLine1: string;
17+
18+
@ApiProperty({
19+
description: 'Address line 2',
20+
example: null,
21+
})
22+
readonly addressLine2: string | null;
23+
24+
@ApiProperty({
25+
description: 'Address line 3',
26+
example: null,
27+
})
28+
readonly addressLine3: string | null;
29+
30+
@ApiProperty({
31+
description: 'Locality, Town',
32+
example: 'LONDON',
33+
})
34+
readonly locality: string | null;
35+
36+
@ApiProperty({
37+
description: 'Postcode',
38+
example: 'SW1A 2AQ',
39+
})
40+
readonly postalCode: string | null;
41+
42+
@ApiProperty({
43+
description: 'Country of address record',
44+
example: null,
45+
})
46+
readonly country: string | null;
47+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { BadRequestException, Controller, Get, Query } from '@nestjs/common';
2+
import { ApiNotFoundResponse, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
3+
4+
import { GetSearchPostcodeOrdnanceSurveyQueryDto } from '@ukef/helper-modules/ordnance-survey/dto/get-search-postcode-query.dto';
5+
import { GeospatialService } from './geospatial.service';
6+
import { GetAddressByPostcodeQueryDto } from './dto/get-address-by-postcode-query.dto';
7+
import { GetSearchAddressesResponse, GetSearchAddressesResponseItem } from './dto/get-search-addresses-response.dto';
8+
9+
@ApiTags('geospatial')
10+
@Controller('geospatial')
11+
export class GeospatialController {
12+
constructor(private readonly geospatialService: GeospatialService) {}
13+
14+
@Get('addresses/postcode')
15+
@ApiOperation({
16+
summary: "A search based on a property's postcode. Will accept a full postcode consisting of the area, district, sector and unit e.g. SO16 0AS.",
17+
})
18+
@ApiResponse({
19+
status: 200,
20+
description: 'AddressBase® Premium Basic Land and Property Units (BLPUs) can reference two types of address and with the OS Places API it is possible to search for one at a time, or both. These are the Delivery Point Address (DPA) and the Land and Property Identifier (LPI).',
21+
type: [GetSearchAddressesResponseItem],
22+
})
23+
@ApiNotFoundResponse({
24+
description: 'Customer not found.',
25+
})
26+
getGeospatial(@Query() query: GetAddressByPostcodeQueryDto): Promise<GetSearchAddressesResponse> {
27+
return this.geospatialService.getAddressesByPostcode(query.postcode);
28+
}
29+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { Module } from '@nestjs/common';
2+
import { OrdnanceSurveyModule } from '@ukef/helper-modules/ordnance-survey/ordnance-survey.module';
3+
4+
import { GeospatialController } from './geospatial.controller';
5+
import { GeospatialService } from './geospatial.service';
6+
7+
@Module({
8+
imports: [OrdnanceSurveyModule],
9+
controllers: [GeospatialController],
10+
providers: [GeospatialService],
11+
})
12+
export class GeospatialModule {}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { Injectable } from '@nestjs/common';
2+
import { OrdnanceSurveyService } from '@ukef/helper-modules/ordnance-survey/ordnance-survey.service';
3+
4+
import { GetSearchAddressesResponse } from './dto/get-search-addresses-response.dto';
5+
6+
@Injectable()
7+
export class GeospatialService {
8+
constructor(private readonly ordnanceSurveyService: OrdnanceSurveyService) {}
9+
10+
async getAddressesByPostcode(postcode: string): Promise<GetSearchAddressesResponse> {
11+
let addresses = [];
12+
const response = await this.ordnanceSurveyService.getAddressesByPostcode(postcode);
13+
14+
response.results.forEach((item) => {
15+
// if (item.DPA.LANGUAGE === (req.query.language ? req.query.language : 'EN')) {
16+
if (item.DPA.LANGUAGE === 'EN') {
17+
// Ordnance survey sends duplicated results with the welsh version too via 'CY'
18+
19+
addresses.push({
20+
organisationName: item.DPA.ORGANISATION_NAME || null,
21+
addressLine1: `${item.DPA.BUILDING_NAME || ''} ${item.DPA.BUILDING_NUMBER || ''} ${item.DPA.THOROUGHFARE_NAME || ''}`.trim(),
22+
addressLine2: item.DPA.DEPENDENT_LOCALITY || null,
23+
addressLine3: null, // keys to match registered Address as requested, but not available in OS Places
24+
locality: item.DPA.POST_TOWN || null,
25+
postalCode: item.DPA.POSTCODE || null,
26+
country: null, // keys to match registered Address as requested, but not available in OS Places
27+
});
28+
}
29+
});
30+
31+
return addresses;
32+
}
33+
}

0 commit comments

Comments
 (0)