Skip to content

models: Replacing epsg.io API endpoint #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 17 additions & 27 deletions src/Models/EpsgInfo.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
/*
* Filename: EpsgInfo.js
* Project: TomorrowNow
* Project: OpenPlains
* File Created: Thursday May 26th 2022
* Author: Corey White (smortopahri@gmail.com)
* Maintainer: Corey White
* -----
* Last Modified: Thu May 26 2022
* Last Modified: Wed Feb 19 2025
* Modified By: Corey White
* -----
* License: GPLv3
Expand Down Expand Up @@ -33,32 +33,22 @@
/**
* Class representing espg info return by epsg.io query.
*/
export class EpsgInfo {
export class EpsgInfo {
/**
* Create an EpsgInfo
* @param {String} code - The epsg code
* @param {String} kind - The kind of projection e.g. CRS-GEOGCRS
* @param {Array | String} [bbox = ""] - The bounding box of the projection e.g. [90, -180, -90, 180]
* @param {String} [wkt = ""] - The wkt represention of the projection
* @param {String} [unit = ""] - The measurment unit e.g. degree, meter, feet.
* @param {String} [proj4 = ""] - The proj4 representation e.g. +proj=longlat +datum=WGS84 +no_def
* @param {String} [name = ""] - The projection name. e.g. WGS 84
* @param {String} [area = ""] - The area of the projection e.g. World.
* @param {Number} [default_trans = 0] - Default transform coordinates.
* @param {Array} [trans = []] - Array of transform coordinates
* @param {String} [accuracy = ""] - The accuracy
* @param {Object} data - The data object containing EPSG information
*/
constructor({code, kind, bbox = "", wkt = "", unit = "", proj4 ="", name = "", area = "", default_trans = 0, trans = [], accuracy}) {
this.code = code;
this.kind = kind;
this.bbox = Array.isArray(bbox) ? bbox : null;
this.wkt = wkt;
this.unit = unit;
this.proj4 = proj4;
this.name = name;
this.area = area;
this.defaultTrans = default_trans;
this.trans = [...trans];
this.accuracy = accuracy;
constructor(data) {
this.code = data.id.code;
this.kind = data.kind;
this.bbox = Array.isArray(data.bbox) ? data.bbox : null;
this.wkt = data.exports.wkt;
this.unit = data.unit;
this.proj4 = data.exports.proj4;
this.name = data.name;
this.area = data.area;
this.defaultTrans = data.default_transformation.code;
this.trans = [...data.transformations];
this.accuracy = data.accuracy;
}
}
}
64 changes: 26 additions & 38 deletions src/Models/ProjectionInfoModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* Author: Corey White (smortopahri@gmail.com)
* Maintainer: Corey White
* -----
* Last Modified: Mon Sep 12 2022
* Last Modified: Wed Feb 19 2025
* Modified By: Corey White
* -----
* License: GPLv3
Expand Down Expand Up @@ -37,64 +37,52 @@ import { EpsgSearchResponse } from "./EpsgSearchResponse";
* Actinia class mapping representing the schema to define projection information as JSON input in POST requests
*/
export class ProjectionInfoModel {
static EPSGIO_BASE_URL = "https://epsg.io/"
static MAPTILER_BASE_URL = "https://api.maptiler.com/";

/**
* Create a ProjectionInfoModel instance
* @param {Object}
* @param {String} epsg The EPSG code of the projection that should be used to create a location.
* @param {Object} param0
* @param {String} param0.epsg The EPSG code of the projection that should be used to create a location.
*/
constructor({epsg}) {
constructor({ epsg }) {
this.epsg = epsg;
this.projectionDetails = {}
this.projectionDetails = {};
}

/**
* Fetch details about projection from epsg.io
* @returns ProjectionInfoModel with parameter projectionDetails containing projection details
* @returns {Promise<ProjectionInfoModel>} ProjectionInfoModel with parameter projectionDetails containing projection details
*/
async fetchDetails() {
let epsg = this.epsg
const results = await ProjectionInfoModel.searchEpsg(epsg).results;

if (results) {
this.projectionDetails = results.map(result => {
let projDetails = {};
if (result) {
const code = result.code;
const name = result.name;
const proj4def = result.proj4;
const bbox = result.bbox;

if (code && code.length > 0 && proj4def && proj4def.length > 0 && bbox && bbox.length === 4) {
projDetails = {
code,
name,
proj4def,
bbox
}
}
}
return projDetails;
})
const response = await ProjectionInfoModel.searchEpsg(this.epsg);

if (response.results) {
this.projectionDetails = response.results
.filter(result => result && result.id.code && result.exports.proj4 && result.bbox && result.bbox.length === 4)
.map(result => ({
code: result.id.code,
name: result.name,
proj4def: result.exports.proj4,
bbox: result.bbox
}));
}
return this
return this;
}

/**
* Search for details for a specific epsg code.
* @param {String} epsg
* @returns {EpsgSearchResponse} Repsone from epsg.io or error response.
* @returns {Promise<EpsgSearchResponse>} Response from epsg.io or error response.
*/
static async searchEpsg(epsg) {
const searchPath = "/coordinates/search/";
try {
const url = new URL(`${this.EPSGIO_BASE_URL}?format=json&q=${epsg}`)
const url = new URL(`${this.MAPTILER_BASE_URL}${searchPath}${epsg}.json`);
const res = await fetch(url);
const data = await res.json();
const response = await new EpsgSearchResponse({...data})
return response
}
catch (e) {
return new EpsgSearchResponse(data);
} catch (e) {
return e;
}
}
}
}
16 changes: 9 additions & 7 deletions src/Models/ProjectionInfoModel.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* Author: Corey White (smortopahri@gmail.com)
* Maintainer: Corey White
* -----
* Last Modified: Mon Sep 12 2022
* Last Modified: Wed Feb 19 2025
* Modified By: Corey White
* -----
* License: GPLv3
Expand Down Expand Up @@ -34,7 +34,6 @@ import { ProjectionInfoModel } from './ProjectionInfoModel';
import { EpsgSearchResponse } from './EpsgSearchResponse';
import { EpsgInfo } from './EpsgInfo';


function setupFetchStub(data) {
return function fetchStub() {
return new Promise((resolve) => {
Expand All @@ -49,8 +48,7 @@ function setupFetchStub(data) {
}

const MOCK_EPSG_RESPONSE = {
"status": "ok",
"number_result": 1,
"total": 1,
"results": [
{
"code": "4326",
Expand Down Expand Up @@ -85,15 +83,19 @@ describe("ProjectionInfoModel", ()=> {
expect(typeof projectionInfo.projectionDetails).toBe('object')
})

test("ProjectionInfoModel.fetchDetails() returns a Promise", ()=> {
expect(projectionInfo.fetchDetails() instanceof Promise).toBeTruthy()
})

test('ProjectionInfoModel.searchEpsg(4326) searches epsg.io and returns data', async () => {

global.fetch = jest.fn().mockImplementation(setupFetchStub(MOCK_EPSG_RESPONSE))
const json = await ProjectionInfoModel.searchEpsg(wgs84.epsg)
expect(json instanceof EpsgSearchResponse).toBeTruthy()
expect(json.results).toEqual(MOCK_EPSG_RESPONSE.results)
expect(json.results.length).toEqual(1)
expect(json.results[0] instanceof EpsgInfo).toBeTruthy()
global.fetch.mockClear()
delete global.fetch
})
})
})

Loading