1 | import FollowablePromise from './followable-promise';
|
2 | import Representor from './representor/base';
|
3 | import HalRepresentor from './representor/hal';
|
4 | import HtmlRepresentor from './representor/html';
|
5 | import JsonApiRepresentor from './representor/jsonapi';
|
6 | import Resource from './resource';
|
7 | import { ContentType, KettingInit } from './types';
|
8 | import FetchHelper from './utils/fetch-helper';
|
9 | import './utils/fetch-polyfill';
|
10 | import { resolve } from './utils/url';
|
11 |
|
12 |
|
13 |
|
14 |
|
15 | export default class Ketting {
|
16 |
|
17 | |
18 |
|
19 |
|
20 | bookMark: string;
|
21 |
|
22 | |
23 |
|
24 |
|
25 |
|
26 |
|
27 | resourceCache: { [url: string]: Resource };
|
28 |
|
29 | |
30 |
|
31 |
|
32 |
|
33 |
|
34 | contentTypes: ContentType[];
|
35 |
|
36 | |
37 |
|
38 |
|
39 | private fetchHelper: FetchHelper;
|
40 |
|
41 | constructor(bookMark: string, options?: KettingInit) {
|
42 |
|
43 | if (typeof options === 'undefined') {
|
44 | options = {};
|
45 | }
|
46 |
|
47 | this.resourceCache = {};
|
48 |
|
49 | this.contentTypes = [
|
50 | {
|
51 | mime: 'application/hal+json',
|
52 | representor: 'hal',
|
53 | q: '1.0',
|
54 | },
|
55 | {
|
56 | mime: 'application/vnd.api+json',
|
57 | representor: 'jsonapi',
|
58 | q: '0.9',
|
59 | },
|
60 | {
|
61 | mime: 'application/json',
|
62 | representor: 'hal',
|
63 | q: '0.8',
|
64 | },
|
65 | {
|
66 | mime: 'text/html',
|
67 | representor: 'html',
|
68 | q: '0.7',
|
69 | }
|
70 | ];
|
71 |
|
72 | this.bookMark = bookMark;
|
73 | this.fetchHelper = new FetchHelper(options, this.beforeRequest.bind(this));
|
74 |
|
75 | }
|
76 |
|
77 | |
78 |
|
79 |
|
80 | follow(rel: string, variables?: object): FollowablePromise {
|
81 |
|
82 | return this.getResource().follow(rel, variables);
|
83 |
|
84 | }
|
85 |
|
86 | |
87 |
|
88 |
|
89 |
|
90 |
|
91 |
|
92 |
|
93 |
|
94 |
|
95 | go(uri?: string): Resource {
|
96 |
|
97 | if (typeof uri === 'undefined') {
|
98 | uri = '';
|
99 | }
|
100 | uri = resolve(this.bookMark, uri);
|
101 |
|
102 | if (!this.resourceCache[uri]) {
|
103 | this.resourceCache[uri] = new Resource(this, uri);
|
104 | }
|
105 |
|
106 | return this.resourceCache[uri];
|
107 |
|
108 | }
|
109 |
|
110 | |
111 |
|
112 |
|
113 |
|
114 |
|
115 |
|
116 | getResource(uri?: string): Resource {
|
117 |
|
118 | return this.go(uri);
|
119 |
|
120 | }
|
121 |
|
122 | |
123 |
|
124 |
|
125 |
|
126 |
|
127 | fetch(input: string|Request, init?: RequestInit): Promise<Response> {
|
128 |
|
129 | return this.fetchHelper.fetch(
|
130 | input,
|
131 | init
|
132 | );
|
133 |
|
134 | }
|
135 |
|
136 | |
137 |
|
138 |
|
139 |
|
140 |
|
141 |
|
142 | getRepresentor(contentType: string): typeof Representor {
|
143 |
|
144 | if (contentType.indexOf(';') !== -1) {
|
145 | contentType = contentType.split(';')[0];
|
146 | }
|
147 | contentType = contentType.trim();
|
148 | const result = this.contentTypes.find(item => {
|
149 | return item.mime === contentType;
|
150 | });
|
151 |
|
152 | if (!result) {
|
153 | throw new Error('Could not find a representor for contentType: ' + contentType);
|
154 | }
|
155 |
|
156 | switch (result.representor) {
|
157 | case 'html' :
|
158 | return HtmlRepresentor;
|
159 | case 'hal' :
|
160 | return HalRepresentor;
|
161 | case 'jsonapi' :
|
162 | return JsonApiRepresentor;
|
163 | default :
|
164 | throw new Error('Unknown representor: ' + result.representor);
|
165 |
|
166 | }
|
167 |
|
168 | }
|
169 |
|
170 |
|
171 | |
172 |
|
173 |
|
174 | getAcceptHeader(): string {
|
175 |
|
176 | return this.contentTypes
|
177 | .map( contentType => {
|
178 | let item = contentType.mime;
|
179 | if (contentType.q) { item += ';q=' + contentType.q; }
|
180 | return item;
|
181 | } )
|
182 | .join(', ');
|
183 |
|
184 | }
|
185 |
|
186 | beforeRequest(request: Request): void {
|
187 |
|
188 | const safeMethods = ['GET', 'HEAD', 'OPTIONS', 'PRI', 'PROPFIND', 'REPORT', 'SEARCH', 'TRACE'];
|
189 | if (safeMethods.includes(request.method)) {
|
190 | return;
|
191 | }
|
192 |
|
193 | if (request.url in this.resourceCache) {
|
194 |
|
195 | this.resourceCache[request.url].clearCache();
|
196 | }
|
197 | }
|
198 |
|
199 | }
|