Skip to content

Commit

Permalink
Support retrieving conformance classes from GET /conformance, add mig…
Browse files Browse the repository at this point in the history
…ration hook, helper to make links absolute, fix tests
  • Loading branch information
m-mohr committed Aug 4, 2023
1 parent 3c83cf0 commit f74d001
Show file tree
Hide file tree
Showing 5 changed files with 254 additions and 107 deletions.
65 changes: 48 additions & 17 deletions openeo.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,9 @@ declare module OpenEO {
* Creates an instance of this object.
*
* @param {Connection} connection - A Connection object representing an established connection to an openEO back-end.
* @param {Array} properties - A mapping from the API property names to the JS client property names (usually to convert between snake_case and camelCase), e.g. `["id", "title", ["process_graph", "processGraph"]]`
* @param {Array.<string|Array.<string>>} properties - A mapping from the API property names to the JS client property names (usually to convert between snake_case and camelCase), e.g. `["id", "title", ["process_graph", "processGraph"]]`
*/
constructor(connection: Connection, properties?: any[]);
constructor(connection: Connection, properties?: Array<string | Array<string>>);
/**
* @protected
* @type {Connection}
Expand Down Expand Up @@ -312,17 +312,32 @@ declare module OpenEO {
* @type {object.<string, *>}
*/
private data;
/**
* @private
* @ignore
* @type {object.<string, string>}
*/
private featureMap;
/**
* @private
* @type {Array.<string>}
*/
private features;
/**
* @private
* @ignore
* @type {object.<string, string>}
* Validates the capabilities.
*
* Throws an error in case of an issue, otherwise just passes.
*
* @protected
* @throws {Error}
*/
private featureMap;
protected validate(): void;
/**
* Initializes the class.
*
* @protected
*/
protected init(): void;
/**
* Returns the capabilities response as a JSON serializable representation of the data that is API compliant.
*
Expand Down Expand Up @@ -390,6 +405,14 @@ declare module OpenEO {
* @returns {Array.<BillingPlan>} Billing plans
*/
listPlans(): Array<BillingPlan>;
/**
* Migrates a response, if required.
*
* @param {AxiosResponse} response
* @protected
* @returns {AxiosResponse}
*/
protected migrate(response: AxiosResponse): AxiosResponse;
}
/**
* The Authentication Provider for OpenID Connect.
Expand Down Expand Up @@ -1504,11 +1527,11 @@ declare module OpenEO {
/**
* Converts a sorted array of arguments to an object with the respective parameter names.
*
* @param {Array} processArgs
* @param {Array.<object.<string, *>>} processArgs
* @returns {object.<string, *>}
* @throws {Error}
*/
namedArguments(processArgs: any[]): object<string, any>;
namedArguments(processArgs: Array<object<string, any>>): object<string, any>;
/**
* Checks the arguments given for parameters and add them to the process.
*
Expand Down Expand Up @@ -1738,10 +1761,10 @@ declare module OpenEO {
/**
* Gets the callback parameter specifics from the parent process.
*
* @returns {Array}
* @returns {Array.<object.<string,*>>}
* @todo Should this also pass callback parameters from parents until root is reached?
*/
getParentCallbackParameters(): any[];
getParentCallbackParameters(): Array<object<string, any>>;
/**
* Adds a parameter to the list of process parameters.
*
Expand Down Expand Up @@ -1880,11 +1903,12 @@ declare module OpenEO {
* @async
* @protected
* @returns {Promise<Capabilities>} Capabilities
* @throws {Error}
*/
protected init(): Promise<Capabilities>;
/**
* Refresh the cache for processes.
*
*
* @async
* @protected
* @returns {Promise}
Expand Down Expand Up @@ -1968,7 +1992,7 @@ declare module OpenEO {
* 2. Lower left corner, coordinate axis 2
* 3. Upper right corner, coordinate axis 1
* 4. Upper right corner, coordinate axis 2
* @param {?Array.<*>} [temporalExtent=null] - Limits the items to the specified temporal interval.
* @param {?Array} [temporalExtent=null] - Limits the items to the specified temporal interval.
* The interval has to be specified as an array with exactly two elements (start, end) and
* each must be either an RFC 3339 compatible string or a Date object.
* Also supports open intervals by setting one of the boundaries to `null`, but never both.
Expand Down Expand Up @@ -2346,21 +2370,28 @@ declare module OpenEO {
* Adds links and federation:missing.
*
* @protected
* @param {Array} arr
* @param {Array.<*>} arr
* @param {object.<string, *>} response
* @returns {ResponseArray}
*/
protected _toResponseArray(arr: any[], response: object<string, any>): any;
protected _toResponseArray(arr: Array<any>, response: object<string, any>): any;
/**
* Get the a link with the given rel type.
*
* @protected
* @param {Array.<Link>} links - An array of links.
* @param {string} rel - Relation type to find, defaults to `next`.
* @param {string|Array.<string>} rel - Relation type(s) to find.
* @returns {string | null}
* @throws {Error}
*/
protected _getLinkHref(links: Array<Link>, rel?: string): string | null;
getHrefForRel(links: Array<Link>, rel: string | Array<string>): string | null;
/**
* Makes all links in the list absolute.
*
* @param {Array.<Link>} links - An array of links.
* @param {?string|AxiosResponse} [base=null] - The base url to use for relative links.
* @returns {Array.<Link>}
*/
makeLinksAbsolute(links: Array<Link>, base?: string | AxiosResponse) : Array.<Link>;
/**
* Sends a GET request.
*
Expand Down
176 changes: 106 additions & 70 deletions src/capabilities.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,61 @@
const Utils = require('@openeo/js-commons/src/utils');

const FEATURE_MAP = {
// Discovery
capabilities: true,
listFileTypes: 'get /file_formats',
listServiceTypes: 'get /service_types',
listUdfRuntimes: 'get /udf_runtimes',
// Collections
listCollections: 'get /collections',
describeCollection: 'get /collections/{collection_id}',
listCollectionItems: 'get /collections/{collection_id}/items',
// Processes
listProcesses: 'get /processes',
describeProcess: 'get /processes',
// Auth / Account
listAuthProviders: true,
authenticateOIDC: 'get /credentials/oidc',
authenticateBasic: 'get /credentials/basic',
describeAccount: 'get /me',
// Files
listFiles: 'get /files',
getFile: 'get /files', // getFile is a virtual function and doesn't request an endpoint, but get /files should be available nevertheless.
uploadFile: 'put /files/{path}',
downloadFile: 'get /files/{path}',
deleteFile: 'delete /files/{path}',
// User-Defined Processes
validateProcess: 'post /validation',
listUserProcesses: 'get /process_graphs',
describeUserProcess: 'get /process_graphs/{process_graph_id}',
getUserProcess: 'get /process_graphs/{process_graph_id}',
setUserProcess: 'put /process_graphs/{process_graph_id}',
replaceUserProcess: 'put /process_graphs/{process_graph_id}',
deleteUserProcess: 'delete /process_graphs/{process_graph_id}',
// Processing
computeResult: 'post /result',
listJobs: 'get /jobs',
createJob: 'post /jobs',
listServices: 'get /services',
createService: 'post /services',
getJob: 'get /jobs/{job_id}',
describeJob: 'get /jobs/{job_id}',
updateJob: 'patch /jobs/{job_id}',
deleteJob: 'delete /jobs/{job_id}',
estimateJob: 'get /jobs/{job_id}/estimate',
debugJob: 'get /jobs/{job_id}/logs',
startJob: 'post /jobs/{job_id}/results',
stopJob: 'delete /jobs/{job_id}/results',
listResults: 'get /jobs/{job_id}/results',
downloadResults: 'get /jobs/{job_id}/results',
// Web services
describeService: 'get /services/{service_id}',
getService: 'get /services/{service_id}',
updateService: 'patch /services/{service_id}',
deleteService: 'delete /services/{service_id}',
debugService: 'get /services/{service_id}/logs',
};

/**
* Capabilities of a back-end.
*/
Expand All @@ -12,91 +68,60 @@ class Capabilities {
* @throws {Error}
*/
constructor(data) {
if(!Utils.isObject(data)) {
throw new Error("No capabilities retrieved.");
}
if(!data.api_version) {
throw new Error("Invalid capabilities: No API version retrieved");
}
if(!Array.isArray(data.endpoints)) {
throw new Error("Invalid capabilities: No endpoints retrieved");
}

/**
* @private
* @type {object.<string, *>}
*/
this.data = data;

/**
* @private
* @ignore
* @type {object.<string, string>}
*/
this.featureMap = FEATURE_MAP;

/**
* @private
* @type {Array.<string>}
*/
this.features = [];

this.validate();
this.init();
}

/**
* Validates the capabilities.
*
* Throws an error in case of an issue, otherwise just passes.
*
* @protected
* @throws {Error}
*/
validate() {
if(!Utils.isObject(this.data)) {
throw new Error("No capabilities retrieved.");
}
else if(!this.data.api_version) {
throw new Error("Invalid capabilities: No API version retrieved");
}
else if(!Array.isArray(this.data.endpoints)) {
throw new Error("Invalid capabilities: No endpoints retrieved");
}
}

/**
* Initializes the class.
*
* @protected
*/
init() {
this.features = this.data.endpoints
// Flatten features to be compatible with the feature map.
.map(e => e.methods.map(method => (method + ' ' + e.path).toLowerCase()))
.reduce((flat, next) => flat.concat(next), []); // .flat(1) once browser support for ECMAscript 10/2019 gets better

/**
* @private
* @ignore
* @type {object.<string, string>}
*/
this.featureMap = {
// Discovery
capabilities: true,
listFileTypes: 'get /file_formats',
listServiceTypes: 'get /service_types',
listUdfRuntimes: 'get /udf_runtimes',
// Collections
listCollections: 'get /collections',
describeCollection: 'get /collections/{collection_id}',
listCollectionItems: 'get /collections/{collection_id}/items',
// Processes
listProcesses: 'get /processes',
describeProcess: 'get /processes',
// Auth / Account
listAuthProviders: true,
authenticateOIDC: 'get /credentials/oidc',
authenticateBasic: 'get /credentials/basic',
describeAccount: 'get /me',
// Files
listFiles: 'get /files',
getFile: 'get /files', // getFile is a virtual function and doesn't request an endpoint, but get /files should be available nevertheless.
uploadFile: 'put /files/{path}',
downloadFile: 'get /files/{path}',
deleteFile: 'delete /files/{path}',
// User-Defined Processes
validateProcess: 'post /validation',
listUserProcesses: 'get /process_graphs',
describeUserProcess: 'get /process_graphs/{process_graph_id}',
getUserProcess: 'get /process_graphs/{process_graph_id}',
setUserProcess: 'put /process_graphs/{process_graph_id}',
replaceUserProcess: 'put /process_graphs/{process_graph_id}',
deleteUserProcess: 'delete /process_graphs/{process_graph_id}',
// Processing
computeResult: 'post /result',
listJobs: 'get /jobs',
createJob: 'post /jobs',
listServices: 'get /services',
createService: 'post /services',
getJob: 'get /jobs/{job_id}',
describeJob: 'get /jobs/{job_id}',
updateJob: 'patch /jobs/{job_id}',
deleteJob: 'delete /jobs/{job_id}',
estimateJob: 'get /jobs/{job_id}/estimate',
debugJob: 'get /jobs/{job_id}/logs',
startJob: 'post /jobs/{job_id}/results',
stopJob: 'delete /jobs/{job_id}/results',
listResults: 'get /jobs/{job_id}/results',
downloadResults: 'get /jobs/{job_id}/results',
// Web services
describeService: 'get /services/{service_id}',
getService: 'get /services/{service_id}',
updateService: 'patch /services/{service_id}',
deleteService: 'delete /services/{service_id}',
debugService: 'get /services/{service_id}/logs',
};
}

/**
Expand Down Expand Up @@ -215,6 +240,17 @@ class Capabilities {
return [];
}
}

/**
* Migrates a response, if required.
*
* @param {AxiosResponse} response
* @protected
* @returns {AxiosResponse}
*/
migrate(response) { // eslint-disable-line no-unused-vars
return response;
}
}

module.exports = Capabilities;
Loading

0 comments on commit f74d001

Please sign in to comment.