Skip to content

Commit

Permalink
feat(tiler): Exclude layers from style json. BM-730 (#2629)
Browse files Browse the repository at this point in the history
* Exclude layers from style json

* Some improvements

* fix(server): correctly forward array query strings to the lambda function (#2630)

* fix(server): correctly forward array query strings to the lambda function

* refactor: fix api key forwarding too

* Create a new layer instead of modify it

* Exclude layers from style json

* Some improvements

* Create a new layer instead of modify it

* Remove console log

* Remove exclude parameters from landing page.

* some refinement.

Co-authored-by: Blayne Chard <bchard@linz.govt.nz>
  • Loading branch information
Wentao-Kuang and blacha authored Jan 16, 2023
1 parent d95537f commit 4683358
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 51 deletions.
2 changes: 1 addition & 1 deletion packages/_infra/src/edge/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export class EdgeStack extends cdk.Stack {
forwardedValues: {
/** Forward all query strings but do not use them for caching */
queryString: true,
queryStringCacheKeys: ['config'],
queryStringCacheKeys: ['config', 'exclude'],
},
lambdaFunctionAssociations: [],
},
Expand Down
2 changes: 1 addition & 1 deletion packages/config/src/config/vector.style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ interface SourceRaster {
/**
* https://docs.mapbox.com/mapbox-gl-js/style-spec/layers/
*/
interface Layer {
export interface Layer {
id: string;
type: string;
filter?: unknown[];
Expand Down
2 changes: 1 addition & 1 deletion packages/config/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export {
TileResizeKernel,
TileSetType,
} from './config/tile.set.js';
export { ConfigVectorStyle, Sources, StyleJson } from './config/vector.style.js';
export { ConfigVectorStyle, Layer, Sources, StyleJson } from './config/vector.style.js';
export { ConfigProviderDynamo } from './dynamo/dynamo.config.js';
export { ConfigDynamoBase } from './dynamo/dynamo.config.base.js';
export { ConfigProviderMemory, ConfigBundled } from './memory/memory.config.js';
Expand Down
144 changes: 100 additions & 44 deletions packages/lambda-tiler/src/routes/__tests__/tile.style.json.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,60 +28,115 @@ o.spec('/v1/styles', () => {
o(res.status).equals(404);
});

o('should serve style json', async () => {
const request = mockRequest('/v1/tiles/topographic/Google/style/topographic.json', 'get', Api.header);

const fakeStyle: StyleJson = {
version: 8,
id: 'test',
name: 'topographic',
sources: {
basemaps_vector: {
type: 'vector',
url: `/vector`,
},
basemaps_raster: {
type: 'raster',
tiles: [`/raster`],
const fakeStyle: StyleJson = {
version: 8,
id: 'test',
name: 'topographic',
sources: {
basemaps_vector: {
type: 'vector',
url: `/vector`,
},
basemaps_raster: {
type: 'raster',
tiles: [`/raster`],
},
basemaps_raster_encode: {
type: 'raster',
tiles: [`/raster/{z}/{x}/{y}.webp`], // Shouldn't encode the {}
},
test_vector: {
type: 'vector',
url: 'vector.url.co.nz',
},
test_raster: {
type: 'raster',
tiles: ['raster.url.co.nz'],
},
},
layers: [
{
layout: {
visibility: 'visible',
},
basemaps_raster_encode: {
type: 'raster',
tiles: [`/raster/{z}/{x}/{y}.webp`], // Shouldn't encode the {}
paint: {
'background-color': 'rgba(206, 229, 242, 1)',
},
test_vector: {
type: 'vector',
url: 'vector.url.co.nz',
id: 'Background1',
type: 'background',
minzoom: 0,
},
{
layout: {
visibility: 'visible',
},
test_raster: {
type: 'raster',
tiles: ['raster.url.co.nz'],
paint: {
'background-color': 'rgba(206, 229, 242, 1)',
},
id: 'Background2',
type: 'background',
minzoom: 0,
},
layers: [
{
layout: {
visibility: 'visible',
},
paint: {
'background-color': 'rgba(206, 229, 242, 1)',
},
id: 'Background',
type: 'background',
minzoom: 0,
{
layout: {
visibility: 'visible',
},
],
glyphs: '/glyphs',
sprite: '/sprite',
metadata: { id: 'test' },
};
paint: {
'background-color': 'rgba(206, 229, 242, 1)',
},
id: 'Background3',
type: 'background',
minzoom: 0,
},
],
glyphs: '/glyphs',
sprite: '/sprite',
metadata: { id: 'test' },
};

const fakeRecord = {
id: 'st_topographic',
name: 'topographic',
style: fakeStyle,
};

o('should serve style json', async () => {
config.put(fakeRecord);

const fakeRecord = {
id: 'st_topographic',
name: 'topographic',
style: fakeStyle,
const request = mockRequest('/v1/tiles/topographic/Google/style/topographic.json', 'get', Api.header);

const res = await handler.router.handle(request);
o(res.status).equals(200);
o(res.header('content-type')).equals('application/json');
o(res.header('cache-control')).equals('no-store');

const body = Buffer.from(res.body ?? '', 'base64').toString();
fakeStyle.sources.basemaps_vector = {
type: 'vector',
url: `${host}/vector?api=${Api.key}`,
};
fakeStyle.sources.basemaps_raster = {
type: 'raster',
tiles: [`${host}/raster?api=${Api.key}`],
};
fakeStyle.sources.basemaps_raster_encode = {
type: 'raster',
tiles: [`${host}/raster/{z}/{x}/{y}.webp?api=${Api.key}`],
};

fakeStyle.sprite = `${host}/sprite`;
fakeStyle.glyphs = `${host}/glyphs`;

o(JSON.parse(body)).deepEquals(fakeStyle);
});

o('should serve style json with excluded layers', async () => {
config.put(fakeRecord);
const request = mockUrlRequest(
'/v1/tiles/topographic/Google/style/topographic.json',
'?exclude=background1&exclude=BACKGROUND2',
Api.header,
);

const res = await handler.router.handle(request);
o(res.status).equals(200);
Expand All @@ -104,6 +159,7 @@ o.spec('/v1/styles', () => {

fakeStyle.sprite = `${host}/sprite`;
fakeStyle.glyphs = `${host}/glyphs`;
fakeStyle.layers = [fakeStyle.layers[2]];

o(JSON.parse(body)).deepEquals(fakeStyle);
});
Expand Down
15 changes: 11 additions & 4 deletions packages/lambda-tiler/src/routes/tile.style.json.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ConfigTileSetRaster, Sources, StyleJson, TileSetType } from '@basemaps/config';
import { ConfigTileSetRaster, Layer, Sources, StyleJson, TileSetType } from '@basemaps/config';
import { Env, toQueryString } from '@basemaps/shared';
import { fsa } from '@chunkd/fs';
import { HttpHeader, LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambda';
Expand Down Expand Up @@ -31,7 +31,7 @@ export function convertRelativeUrl(url?: string, apiKey?: string, config?: strin
* @param apiKey api key to inject
* @returns new stylejson
*/
export function convertStyleJson(style: StyleJson, apiKey: string, config: string | null): StyleJson {
export function convertStyleJson(style: StyleJson, apiKey: string, config: string | null, layers?: Layer[]): StyleJson {
const sources: Sources = JSON.parse(JSON.stringify(style.sources));
for (const [key, value] of Object.entries(sources)) {
if (value.type === 'vector') {
Expand All @@ -49,7 +49,7 @@ export function convertStyleJson(style: StyleJson, apiKey: string, config: strin
id: style.id,
name: style.name,
sources,
layers: style.layers,
layers: layers ? layers : style.layers,
metadata: style.metadata ?? {},
glyphs: convertRelativeUrl(style.glyphs, undefined, config),
sprite: convertRelativeUrl(style.sprite, undefined, config),
Expand Down Expand Up @@ -101,6 +101,8 @@ export async function tileSetToStyle(
export async function styleJsonGet(req: LambdaHttpRequest<StyleGet>): Promise<LambdaHttpResponse> {
const apiKey = Validate.apiKey(req);
const styleName = req.params.styleName;
const excludeLayers = req.query.getAll('exclude');
const excluded = new Set(excludeLayers.map((l) => l.toLowerCase()));

// Get style Config from db
const config = await ConfigLoader.load(req);
Expand All @@ -115,7 +117,12 @@ export async function styleJsonGet(req: LambdaHttpRequest<StyleGet>): Promise<La
}

// Prepare sources and add linz source
const style = convertStyleJson(styleConfig.style, apiKey, ConfigLoader.extract(req));
const style = convertStyleJson(
styleConfig.style,
apiKey,
ConfigLoader.extract(req),
styleConfig.style.layers.filter((f) => !excluded.has(f.id.toLowerCase())),
);
const data = Buffer.from(JSON.stringify(style));

const cacheKey = Etag.key(data);
Expand Down

0 comments on commit 4683358

Please sign in to comment.