├── .eslintrc.js ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md ├── labels.json └── workflows │ └── main.yml ├── .gitignore ├── .vscode └── settings.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── native.js ├── package.json ├── src ├── beacon.ts ├── helpers │ ├── errors.ts │ ├── feed.ts │ ├── fp.ts │ ├── json.ts │ ├── query.ts │ ├── request.ts │ ├── response.ts │ ├── typescript.ts │ └── url.ts ├── index.ts ├── internals.ts ├── methods │ ├── collections │ │ ├── index.ts │ │ └── types.ts │ ├── photos │ │ ├── index.ts │ │ └── types.ts │ ├── search │ │ ├── index.ts │ │ └── types │ │ │ ├── request.ts │ │ │ └── response.ts │ ├── topics │ │ ├── index.ts │ │ └── types.ts │ └── users │ │ ├── index.ts │ │ └── types.ts └── types │ ├── entities.ts │ └── request.ts ├── tests ├── __snapshots__ │ └── index.test.ts.snap └── index.test.ts ├── tsconfig.json ├── tsdx.config.js ├── vscode-response-types.png ├── vscode-screenshot.png ├── vscode-screenshot2.png └── yarn.lock /.eslintrc.js: -------------------------------------------------------------------------------- 1 | /** @type {import('eslint').Linter.Config} */ 2 | module.exports = { 3 | extends: ['prettier/@typescript-eslint', 'plugin:prettier/recommended'], 4 | parserOptions: { 5 | project: ['./tsconfig.json'], 6 | }, 7 | rules: { 8 | 'object-shorthand': 2, 9 | 'arrow-body-style': [2, 'as-needed'], 10 | '@typescript-eslint/strict-boolean-expressions': [2], 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # These users will be the default owners for everything in the repo. 2 | # See https://github.com/blog/2392-introducing-code-owners 3 | 4 | * @unsplash/web -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | #### Steps to Reproduce 2 | 3 | - 4 | 5 | #### Observed Behaviour 6 | 7 | - 8 | 9 | > _Image or video please._ 10 | 11 | #### Expected Behaviour 12 | 13 | - 14 | 15 | #### Technical Notes 16 | 17 | - 18 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | #### Overview 2 | 3 | - 4 | - Closes # 5 | 6 | #### Todo 7 | 8 | - 9 | 10 | #### Screenshots/Videos (User Facing Changes) 11 | 12 | > _Insert responsive image(s) and/or video(s)_ 13 | -------------------------------------------------------------------------------- /.github/labels.json: -------------------------------------------------------------------------------- 1 | [ 2 | { "name": "Priority: Critical", "color": "#e11d21" }, 3 | 4 | { "name": "Status: Blocked", "color": "#e11d21" }, 5 | { "name": "Status: On Hold", "color": "#e11d21" }, 6 | { "name": "Status: In Progress", "color": "#fbca04" }, 7 | { "name": "Status: Ready for Review", "color": "#bfe5bf" }, 8 | 9 | { "name": "Type: Bug", "color": "#e11d21" }, 10 | { "name": "Type: Maintenance", "color": "#fbca04" }, 11 | { "name": "Type: Enhancement", "color": "#84b6eb" }, 12 | { "name": "Type: Question", "color": "#cc317c" } 13 | ] 14 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | pull_request: 4 | branches: 5 | - master 6 | push: 7 | branches: 8 | - master 9 | jobs: 10 | build: 11 | name: Build, lint, and test on Node ${{ matrix.node }} and ${{ matrix.os }} 12 | 13 | runs-on: ${{ matrix.os }} 14 | strategy: 15 | matrix: 16 | node: ['10.x', '12.x', '14.x'] 17 | os: [ubuntu-latest, windows-latest, macOS-latest] 18 | 19 | steps: 20 | - name: Checkout repo 21 | uses: actions/checkout@v2 22 | 23 | - name: Use Node ${{ matrix.node }} 24 | uses: actions/setup-node@v1 25 | with: 26 | node-version: ${{ matrix.node }} 27 | 28 | - name: Install deps and build (with cache) 29 | uses: bahmutov/npm-install@v1 30 | 31 | - name: Lint 32 | run: yarn lint 33 | 34 | - name: Test 35 | run: yarn test --ci --coverage --maxWorkers=2 36 | 37 | - name: Build 38 | run: yarn build 39 | 40 | - name: Check size 41 | if: ${{ github.event_name == 'pull_request' && github.base_ref == 'master'}} 42 | uses: andresz1/size-limit-action@v1 43 | with: 44 | github_token: ${{ secrets.GITHUB_TOKEN }} 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | lib 4 | coverage 5 | dist 6 | test.js 7 | 8 | node_modules 9 | *.log 10 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.codeActionsOnSave": { 3 | "source.fixAll.eslint": true 4 | } 5 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 7.0.3 4 | 5 | - Adds response types to all endpoints. 6 | 7 | ## 7.0.0 8 | 9 | This version includes a total TypeScript rewrite of the library, with many breaking changes. If upgrading from a previous version, read carefully. You will not be able to upgrade to v7 without making the necessary adjustments. 10 | 11 | ### Breaking Changes 12 | 13 | - Replaces the `Unsplash` `class` with a named `createApi` function: 14 | 15 | ```ts 16 | // before 17 | import Unsplash from 'unsplash-js'; 18 | const unsplash = new Unsplash({ accessKey: 'MY_ACCESS_KEY' }); 19 | 20 | // after 21 | import { createApi } from 'unsplash-js'; 22 | const unsplash = createApi({ accessKey: 'MY_ACCESS_KEY' }); 23 | // or 24 | import Unsplash from 'unsplash-js'; 25 | const unsplash = Unsplash.createApi({ accessKey: 'MY_ACCESS_KEY' }); 26 | ``` 27 | 28 | - Removes user authentication features from the library. This means that the `createApi` function does not recieve `secret`, `callbackUrl` or `bearerToken`. 29 | 30 | * Removes the following API methods (primarily due to removal of user authentication): 31 | 32 | - `photos`: 33 | - ❌ `likePhoto` 34 | - ❌ `unlikePhoto` 35 | - ❌ `downloadPhoto` (deprecated in 6.3, replaced with `trackDownload`) 36 | - `users`: 37 | - ❌ `statistics` 38 | - `collections`: 39 | - ❌ `createCollection` 40 | - ❌ `updateCollection` 41 | - ❌ `deleteCollection` 42 | - ❌ `addPhotoToCollection` 43 | - ❌ `removePhotoFromCollection` 44 | - `auth`: 45 | - ❌ `getAuthenticationUrl` 46 | - ❌ `userAuthentication` 47 | - ❌ `setBearerToken` 48 | - `currentUser`: 49 | - ❌ `profile` 50 | - ❌ `updateProfile` 51 | - `stats`: 52 | - ❌ `total` 53 | - ❌ `toJson` (the library now takes care of converting the response to JSON). 54 | 55 | * Renames all of the remaining API methods: 56 | 57 | - `search`: 58 | - ⚠️ `photos` --> `getPhotos` 59 | - ⚠️ `users` --> `getUsers` 60 | - ⚠️ `collections` --> `getCollections` 61 | - `photos`: 62 | - ⚠️ `listPhotos` --> `list` 63 | - ⚠️ `getPhoto` --> `get` 64 | - ⚠️ `getRandomPhoto` --> `getRandom` 65 | - ⚠️ `getPhotoStats` --> `getStats` 66 | - `users`: 67 | - ⚠️ `profile` --> `get` 68 | - ⚠️ `photos` --> `getPhotos` 69 | - ⚠️ `likes` --> `getLikes` 70 | - ⚠️ `collections` --> `getCollections` 71 | - `collections`: 72 | - ⚠️ `listCollections` --> `list` 73 | - ⚠️ `getCollection` --> `get` 74 | - ⚠️ `getCollectionPhotos` --> `getPhotos` 75 | - ⚠️ `listRelatedCollections` --> `listRelated` 76 | 77 | - Changes the format of the parameters for **all** API methods. They are now all named parameters within the first argument, instead of multiple arguments. Check the TypeScript types and the [Arguments](./README.md#Arguments) section of the docs for the new parameters format. 78 | - Changes the format of the responses for **all** API methods. The JSON is now parsed and returned, removing the need for the `toJson` helper. Feeds have the "x-total" header added to the response. The library now also performs error-handling: expected errors are returned instead of thrown, along with a description of their source. Check the TypeScript types and the [Response](./README.md#Response) section of the docs for the new response format. 79 | 80 | ### Changes 81 | 82 | - TypeScript support! Everything is now accurately typed (except responses which we plan to add types for soon). 83 | - You can now provide fetch options on a per-call basis using the second parameter. See [Arguments](./README.md#Arguments). 84 | 85 | ## 6.3.0 86 | 87 | ### Changes 88 | 89 | - Deprecate `photos.downloadPhoto` in favor of `photos.trackDownload` to better clarify method usage. `downloadPhoto` will continue to be supported until version 7.0. 90 | 91 | ## 6.2.0 92 | 93 | ### Changes 94 | 95 | - Adds support for [the languages beta](https://changelog.unsplash.com/update/2020/08/21/languages-beta.html) on search 96 | 97 | ```js 98 | unsplash.search.photos('nature', 1, 10, { lang: 'en' }); 99 | ``` 100 | 101 | - Adds support for the [new search filters and ordering](https://changelog.unsplash.com/update/2020/03/04/new-filters.html) 102 | 103 | ```js 104 | unsplash.search.photos('nature', 1, 10, { 105 | orientation: 'landscape', 106 | color: 'green', // new 107 | orderBy: 'relevant', // new 108 | }); 109 | ``` 110 | 111 | - Adds support for [content filtering on search](https://changelog.unsplash.com/update/2020/03/15/content-filtering.html) 112 | 113 | ```js 114 | unsplash.search.photos('nature', 1, 10, { contentFilter: 'high' }); 115 | ``` 116 | 117 | - Removes any references to 'popular' ordering ([due to deprecation](https://changelog.unsplash.com/update/2020/07/09/deprecate-popular.html)) 118 | 119 | ## 6.1.0 120 | 121 | Enables Brotli compression by default. 122 | 123 | ## 6.0 124 | 125 | ### Changes 126 | 127 | - To better clarify the use of `accessKey` when initializing, `applicationId` has been renamed to `accessKey`: 128 | 129 | ```js 130 | // previously 131 | const unsplash = new Unsplash({ 132 | applicationId: '{APP_ACCESS_KEY}', 133 | }); 134 | 135 | // now 136 | const unsplash = new Unsplash({ 137 | accessKey: '{APP_ACCESS_KEY}', 138 | }); 139 | ``` 140 | 141 | - `unsplash.photos.getPhotoStats` now uses the `/photos/:id/statistics` endpoint ([changelog reference](https://changelog.unsplash.com/deprecations/2017/10/05/existing-deprecations.html)) 142 | 143 | - To support additional filters, the `unsplash.search.photos` method signature has been changed to support an optional `filters` object, which currently supports `collections` and `orientation` keys. 144 | 145 | ```js 146 | unsplash.search.photos('nature', 1, 10, { orientation: 'landscape', collections: [1, 2] }); 147 | ``` 148 | 149 | ### Removals 150 | 151 | 6.0 removes deprecated endpoints and parameters to match the changes from [the Unsplash API Changelog](https://changelog.unsplash.com/). Most of these endpoints have been deprecated on the API and removed from `unsplash-js` documentation for 2+ years. 152 | 153 | | Removed Method | Replacement | Reason | 154 | | ------------------------------------------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 155 | | `unsplash.search.all` | None | This endpoint is undocumented publicly and is highly likely to change in the future. Therefore, we don't recommend anyone use this functionality in their applications. | 156 | | `unsplash.photos.listCuratedPhotos` | None | Curated photos were [deprecated in 2017](https://changelog.unsplash.com/deprecations/2018/09/27/curated-collections-deprecation.html), [removed in 2019](https://changelog.unsplash.com/deprecations/2019/09/23/curated-collections-removal.html) | 157 | | `unsplash.photos.searchPhotos` | `unsplash.search.photos` | Replaced by [the new search endpoints in 2017](https://changelog.unsplash.com/deprecations/2017/10/05/existing-deprecations.html) | 158 | | `unsplash.photos.uploadPhoto` | None | Removed for legal compatibility | 159 | | `unsplash.collections.listFeaturedCollections` | `unsplash.collections.listCollections` | Redundant endpoint | 160 | | `unsplash.collections.listCuratedCollections` | None | Curated collections were replaced by collections. [Deprecated in 2017](https://changelog.unsplash.com/deprecations/2018/09/27/curated-collections-deprecation.html), [removed in 2019](https://changelog.unsplash.com/deprecations/2019/09/23/curated-collections-removal.html) | 161 | | `unsplash.collections.getCuratedCollection` | `unsplash.collections.getCollection` | Curated collections were replaced by collections. [Deprecated in 2017](https://changelog.unsplash.com/deprecations/2018/09/27/curated-collections-deprecation.html), [removed in 2019](https://changelog.unsplash.com/deprecations/2019/09/23/curated-collections-removal.html) | 162 | | `unsplash.collections.getCuratedCollectionPhotos` | `unsplash.collections.getCollectionPhotos` | Curated collections were replaced by collections. [Deprecated in 2017](https://changelog.unsplash.com/deprecations/2018/09/27/curated-collections-deprecation.html), [removed in 2019](https://changelog.unsplash.com/deprecations/2019/09/23/curated-collections-removal.html) | 163 | | `unsplash.categories.*` | None | [Categories were deprecated in 2017](https://changelog.unsplash.com/deprecations/2017/10/05/existing-deprecations.html) and [removed from the API in 2017](https://changelog.unsplash.com/deprecations/2018/04/20/categories-eol.html) | 164 | 165 | | Removed Parameter | Method | Reason | 166 | | ----------------- | ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 167 | | `category` | `unsplash.photos.getRandomPhoto` | [Categories were deprecated in 2017](https://changelog.unsplash.com/deprecations/2017/10/05/existing-deprecations.html) and [removed from the API in 2017](https://changelog.unsplash.com/deprecations/2018/04/20/categories-eol.html) | 168 | | `w` | `unsplash.photos.getPhoto`, `unsplash.photos.getRandomPhoto` | [Deprecated in favor of dynamic image URLs](https://changelog.unsplash.com/2019/03/19/image-resizing.html) | 169 | | `h` | `unsplash.photos.getPhoto`, `unsplash.photos.getRandomPhoto` | [Deprecated in favor of dynamic image URLs](https://changelog.unsplash.com/2019/03/19/image-resizing.html) | 170 | | `crop` | `unsplash.photos.getPhoto` | [Deprecated in favor of dynamic image URLs](https://changelog.unsplash.com/2019/03/19/image-resizing.html) | 171 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Unsplash 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Unsplash 2 | 3 | [![npm](https://img.shields.io/npm/v/unsplash-js.svg?style=flat-square)](https://www.npmjs.com/package/unsplash-js) 4 | 5 | Official Javascript wrapper for the [Unsplash API](https://unsplash.com/developers). 6 | 7 | Key Links: 8 | 9 | - Before using the Unsplash API, [register as a developer](https://unsplash.com/developers). 10 | - Before using the Unsplash API, read the [API Guidelines](https://help.unsplash.com/api-guidelines/unsplash-api-guidelines). Specifically, you _must_: 11 | - [hotlink images](https://help.unsplash.com/api-guidelines/more-on-each-guideline/guideline-hotlinking-images) 12 | - [attribute photographers](https://help.unsplash.com/api-guidelines/more-on-each-guideline/guideline-attribution) 13 | - [trigger a download when appropriate](https://help.unsplash.com/api-guidelines/more-on-each-guideline/guideline-triggering-a-download) 14 | - Once you create an application and have an access key, go try the demos: 15 | - [javascript](https://stackblitz.com/edit/unsplash-js-javascript?file=src%2Findex.js) 16 | - [typescript](https://stackblitz.com/edit/unsplash-js-typescript?file=index.tsx) 17 | 18 | ## Documentation 19 | 20 | - [Installation](#installation) 21 | - [Dependencies](#dependencies) 22 | - [Usage](#usage) 23 | - [Types](#types) 24 | - [Instance Methods](#instance-methods) 25 | 26 | ## Installation 27 | 28 | ```bash 29 | $ npm i --save unsplash-js 30 | 31 | # OR 32 | 33 | $ yarn add unsplash-js 34 | ``` 35 | 36 | ## Dependencies 37 | 38 | ### Fetch 39 | 40 | This library depends on [fetch](https://fetch.spec.whatwg.org/) to make requests to the Unsplash API. For environments that don't support fetch, you'll need to provide polyfills of your choosing. Here are the ones we recommend: 41 | 42 | - node implementation: [node-fetch](https://github.com/bitinn/node-fetch) 43 | - browser polyfill: [whatwg-fetch](https://github.com/github/fetch) 44 | 45 | #### Adding polyfills 46 | 47 | `createApi` receives an optional `fetch` parameter. When it is not provided, we rely on the globally scoped `fetch`. 48 | 49 | This means that you can set the polyfills in the global scope: 50 | 51 | ```ts 52 | // server 53 | import fetch from 'node-fetch'; 54 | global.fetch = fetch; 55 | 56 | // browser 57 | import 'whatwg-fetch'; 58 | ``` 59 | 60 | or explicitly provide them as an argument: 61 | 62 | ```ts 63 | import { createApi } from 'unsplash-js'; 64 | import nodeFetch from 'node-fetch'; 65 | 66 | const unsplash = createApi({ 67 | accessKey: 'MY_ACCESS_KEY', 68 | fetch: nodeFetch, 69 | }); 70 | ``` 71 | 72 | Note: we recommend using a version of `node-fetch` higher than `2.4.0` to benefit from Brotli compression. 73 | 74 | #### `node-fetch` and global types 75 | 76 | This library presumes that the following types exist in the global namespace: 77 | 78 | - `fetch` 79 | - `RequestInit` 80 | - `Response` 81 | 82 | By default TypeScript defines these via the `"dom"` type definitions. 83 | 84 | However, if you're targeting Node and you're using `node-fetch` you should omit the `"dom"` type definitions using the [`lib` compiler option](https://www.typescriptlang.org/tsconfig#lib) and then define the required global types manually like so: 85 | 86 | ```ts 87 | import { createApi } from 'unsplash-js'; 88 | import * as nodeFetch from 'node-fetch' 89 | 90 | declare global { 91 | var fetch: typeof nodeFetch.default; 92 | type RequestInit = nodeFetch.RequestInit; 93 | type Response = nodeFetch.Response; 94 | } 95 | global.fetch = nodeFetch.default; 96 | 97 | const unsplash = createApi({ 98 | accessKey: 'MY_ACCESS_KEY', 99 | fetch: nodeFetch.default, 100 | }); 101 | ``` 102 | 103 | Unfortunately this won't work with `node-fetch` v3 due to an issue in `node-fetch`, whereby the global namespace is polluted with the `"dom"` type definitions: https://github.com/node-fetch/node-fetch/issues/1285. 104 | 105 | As a workaround you use a type assertion: 106 | 107 | ```ts 108 | import { createApi } from 'unsplash-js'; 109 | import * as nodeFetch from 'node-fetch' 110 | 111 | const unsplash = createApi({ 112 | accessKey: 'MY_ACCESS_KEY', 113 | fetch: nodeFetch.default as unknown as typeof fetch, 114 | }); 115 | ``` 116 | 117 | ### URL 118 | 119 | This library also depends on the WHATWG URL interface: 120 | 121 | - MDN [docs](https://developer.mozilla.org/en-US/docs/Web/API/URL) for browsers. 122 | - NodeJS [docs](https://nodejs.org/api/url.html). 123 | 124 | Note: Make sure to polyfill this interface if targetting older environments that do not implement it (i.e. Internet Explorer or Node < v8). 125 | 126 | Note 2: For Node, the URL interface exists under `require('url').URL` since [v8](https://nodejs.org/es/blog/release/v8.0.0/#say-hello-to-the-whatwg-url-parser) but was only added to the global scope as of [v10.0.0](https://nodejs.org/docs/latest/api/globals.html#globals_url). If you are using a version between v8.0.0 and v10.0.0, you need to add the class to the global scope before using `unsplash-js`: 127 | 128 | ```js 129 | URL = require('url').URL; 130 | ``` 131 | 132 | ## Usage 133 | 134 | ### Creating an instance 135 | 136 | To create an instance, simply provide an _Object_ with your `accessKey`. 137 | 138 | NOTE: If you're using `unsplash-js` publicly in the browser, you'll need to proxy your requests through your server to sign the requests with the Access Key to abide by the [API Guideline](https://help.unsplash.com/articles/2511245-unsplash-api-guidelines) to keep keys confidential. We provide an `apiUrl` property that lets you do so. You should only need to provide _one_ of those two values in any given scenario. 139 | 140 | ```ts 141 | import { createApi } from 'unsplash-js'; 142 | 143 | // on your node server 144 | const serverApi = createApi({ 145 | accessKey: 'MY_ACCESS_KEY', 146 | //...other fetch options 147 | }); 148 | 149 | // in the browser 150 | const browserApi = createApi({ 151 | apiUrl: 'https://mywebsite.com/unsplash-proxy', 152 | //...other fetch options 153 | }); 154 | ``` 155 | 156 | ### Making a request 157 | 158 | #### Arguments 159 | 160 | All methods have 2 arguments: the first one includes all of the specific parameters for that particular endpoint, while the second allows you to pass down any additional options that you want to provide to `fetch`. On top of that, the `createApi` constructor can receive `fetch` options to be added to _every_ request: 161 | 162 | ```ts 163 | const unsplash = createApi({ 164 | accessKey: 'MY_ACCESS_KEY', 165 | // `fetch` options to be sent with every request 166 | headers: { 'X-Custom-Header': 'foo' }, 167 | }); 168 | 169 | unsplash.photos.get( 170 | { photoId: '123' }, 171 | // `fetch` options to be sent only with _this_ request 172 | { headers: { 'X-Custom-Header-2': 'bar' } }, 173 | ); 174 | ``` 175 | 176 | Example: if you would like to implement [request abortion](https://developer.mozilla.org/en-US/docs/Web/API/AbortController), you can do so like this: 177 | 178 | ```ts 179 | const unsplash = createApi({ 180 | accessKey: 'MY_ACCESS_KEY', 181 | }); 182 | 183 | const controller = new AbortController(); 184 | const signal = controller.signal; 185 | 186 | unsplash.photos.get({ photoId: '123' }, { signal }).catch(err => { 187 | if (err.name === 'AbortError') { 188 | console.log('Fetch aborted'); 189 | } 190 | }); 191 | 192 | controller.abort(); 193 | ``` 194 | 195 | #### Response 196 | 197 | When making a request using this SDK, there are 2 possible outcomes to a request. 198 | 199 | - Error: we return a `result.errors` object containing an array of strings (each one representing one error) and `result.source` describing the origin of the error (e.g. `api`, `decoding`). Typically, you will only have on item in this array. 200 | - Success: we return a `result.response` object containing the data. 201 | - If the request is for a page from a feed, then `result.response.results` will contain the JSON received from API, and `result.response.total` will contain the [`X-total` header value](https://unsplash.com/documentation#per-page-and-total) indicating the total number of items in the feed (not just the page you asked for). 202 | - If the request is something other than a feed, then `result.response` will contain the JSON received from API 203 | 204 | You can inspect which one you have by reading the `result.type` value or checking the contents of `result.errors`/`result.success` 205 | 206 | ```ts 207 | const unsplash = createApi({ accessKey: 'MY_ACCESS_KEY' }); 208 | 209 | // non-feed example 210 | unsplash.photos.get({ photoId: 'foo' }).then(result => { 211 | if (result.errors) { 212 | // handle error here 213 | console.log('error occurred: ', result.errors[0]); 214 | } else { 215 | // handle success here 216 | const photo = result.response; 217 | console.log(photo); 218 | } 219 | }); 220 | 221 | // feed example 222 | unsplash.users.getPhotos({ username: 'foo' }).then(result => { 223 | if (result.errors) { 224 | // handle error here 225 | console.log('error occurred: ', result.errors[0]); 226 | } else { 227 | const feed = result.response; 228 | 229 | // extract total and results array from response 230 | const { total, results } = feed; 231 | 232 | // handle success here 233 | console.log(`received ${results.length} photos out of ${total}`); 234 | console.log('first photo: ', results[0]); 235 | } 236 | }); 237 | ``` 238 | 239 | NOTE: you can also pattern-match on `result.type` whose value will be `error` or `success`: 240 | 241 | ```ts 242 | unsplash.photos.get({ photoId: 'foo' }).then(result => { 243 | switch (result.type) { 244 | case 'error': 245 | console.log('error occurred: ', result.errors[0]); 246 | case 'success': 247 | const photo = result.response; 248 | console.log(photo); 249 | } 250 | }); 251 | ``` 252 | 253 | ## Types 254 | 255 | The types for this library target TypeScript v3.7 and above. 256 | 257 | This library is written in TypeScript. This means that even if you are writing plain JavaScript, you can still get useful and accurate type information. We highly recommend that you setup your environment (using an IDE such as [VSCode](https://code.visualstudio.com/)) to fully benefit from this information: 258 | 259 | ### Function arguments 260 | 261 | ![](./vscode-screenshot2.png) 262 | ![](./vscode-screenshot.png) 263 | 264 | ### Response Types 265 | 266 | ![](./vscode-response-types.png) 267 | 268 | ## Instance Methods 269 | 270 | NOTE: All of the method arguments described here are in the first parameter. See the [arguments](#Arguments) section for more information. 271 | 272 | - [Search](https://github.com/unsplash/unsplash-js#search) 273 | - [Photos](https://github.com/unsplash/unsplash-js#photos) 274 | - [Users](https://github.com/unsplash/unsplash-js#users) 275 | - [Collections](https://github.com/unsplash/unsplash-js#collections) 276 | - [Topics](https://github.com/unsplash/unsplash-js#topics) 277 | 278 | --- 279 | 280 |