UNPKG

observation-js

Version:

A fully-typed TypeScript client for the waarneming.nl API.

199 lines (198 loc) 8.32 kB
export class Observations { #client; /** * @internal */ constructor(client) { this.#client = client; } /** * Helper function to filter out undefined values from params * @private */ filterParams(params) { const filtered = {}; for (const [key, value] of Object.entries(params)) { if (value !== undefined) { filtered[key] = value; } } return filtered; } /** * Retrieves a single observation by its ID. * * @param id The unique identifier of the observation. * @returns A promise that resolves to the observation object. * @throws {AuthenticationError} If the request is not authenticated. * @throws {ApiError} If the request fails. */ async get(id) { return this.#client.request(`observations/${id}`); } /** * Creates a new observation. * * @param payload - The core data for the new observation. * @param options - Optional parameters, including media files to upload synchronously. * @returns A promise that resolves to the newly created observation object. * @throws {AuthenticationError} If the request is not authenticated. * @throws {ApiError} If the request fails. */ async create(payload, options = {}) { const { upload_photos, upload_sounds } = options; if (upload_photos?.length || upload_sounds?.length) { const formData = new FormData(); formData.append('observation', JSON.stringify(payload)); upload_photos?.forEach((photo) => formData.append('upload_photos', photo)); upload_sounds?.forEach((sound) => formData.append('upload_sounds', sound)); return this.#client.request('observations/create-single/', { method: 'POST', body: formData, }); } return this.#client.request('observations/create-single/', { method: 'POST', body: JSON.stringify(payload), headers: { 'Content-Type': 'application/json', }, }); } /** * Updates an existing observation. * * @param id - The unique identifier of the observation to update. * @param payload - The data to update on the observation. * @param options - Optional parameters, including media files to upload synchronously. * @returns A promise that resolves to the updated observation object. * @throws {AuthenticationError} If the request is not authenticated. * @throws {ApiError} If the request fails. */ async update(id, payload, options = {}) { const { upload_photos, upload_sounds } = options; if (upload_photos?.length || upload_sounds?.length) { const formData = new FormData(); formData.append('observation', JSON.stringify(payload)); upload_photos?.forEach((photo) => formData.append('upload_photos', photo)); upload_sounds?.forEach((sound) => formData.append('upload_sounds', sound)); return this.#client.request(`observations/${id}/update/`, { method: 'POST', body: formData, }); } return this.#client.request(`observations/${id}/update/`, { method: 'POST', body: JSON.stringify(payload), headers: { 'Content-Type': 'application/json', }, }); } /** * Deletes an observation by its ID. * * @param id The unique identifier of the observation to delete. * @returns A promise that resolves when the observation is successfully deleted. * @throws {AuthenticationError} If the request is not authenticated. * @throws {ApiError} If the request fails. */ async delete(id) { await this.#client.request(`observations/${id}/delete/`, { method: 'POST', }); } /** * Search/list observations with filtering options. * Note: General observation listing may not be available. Use more specific methods like getBySpecies, getByLocation, etc. * * @param params - Search and filtering parameters. * @returns A promise that resolves to a paginated list of observations. * @throws {ApiError} If the request fails. */ async search(params = {}) { // Try alternative endpoints since general observations/ might not exist if (params.species) { return this.getBySpecies(params.species, params); } if (params.user) { return this.getByUser(params.user, params); } // Fallback to around-point search if lat/lng provided in extended params throw new Error('General observation search not available. Use getBySpecies(), getByUser(), getByLocation(), or getAroundPoint() instead.'); } /** * Retrieves observations for a specific species. * * @param speciesId - The unique identifier of the species. * @param params - Optional filtering parameters. * @returns A promise that resolves to a paginated list of observations. * @throws {ApiError} If the request fails. */ async getBySpecies(speciesId, params = {}) { return this.#client.publicRequest(`species/${speciesId}/observations/`, { params: this.filterParams(params) }); } /** * Retrieves related species observations for a specific species. * Requires authentication. * * @param speciesId - The unique identifier of the species. * @param params - Optional filtering parameters. * @returns A promise that resolves to a paginated list of observations. * @throws {AuthenticationError} If the request is not authenticated. * @throws {ApiError} If the request fails. */ async getRelatedBySpecies(speciesId, params = {}) { return this.#client.request(`species/${speciesId}/related-observations/`, { params: this.filterParams(params) }); } /** * Retrieves observations for a specific user. * If no userId is provided, returns observations for the authenticated user. * Requires authentication. * * @param userId - The unique identifier of the user (optional for current user). * @param params - Optional filtering parameters. * @returns A promise that resolves to a paginated list of observations. * @throws {AuthenticationError} If the request is not authenticated. * @throws {ApiError} If the request fails. */ async getByUser(userId, params = {}) { const endpoint = userId ? `user/${userId}/observations/` : 'user/observations/'; return this.#client.request(endpoint, { params: this.filterParams(params) }); } /** * Retrieves observations for a specific location. * * @param locationId - The unique identifier of the location. * @param params - Optional filtering parameters. * @returns A promise that resolves to a paginated list of observations. * @throws {ApiError} If the request fails. */ async getByLocation(locationId, params = {}) { return this.#client.publicRequest(`locations/${locationId}/observations/`, { params: this.filterParams(params) }); } /** * Retrieves observations around a specific geographic point. * * @param params - Point coordinates and search parameters. * @returns A promise that resolves to a paginated list of observations. * @throws {ApiError} If the request fails. */ async getAroundPoint(params) { return this.#client.publicRequest('observations/around-point/', { params: this.filterParams(params) }); } /** * Retrieves observations that were deleted after a specific timestamp. * Requires authentication. * * @param modifiedAfter - ISO timestamp to get deletions after this point. * @returns A promise that resolves to a list of deleted observation IDs. * @throws {AuthenticationError} If the request is not authenticated. * @throws {ApiError} If the request fails. */ async getDeleted(modifiedAfter) { return this.#client.request('observations/deleted/', { params: { modified_after: modifiedAfter }, }); } }