· 4 years ago · Jul 29, 2021, 05:08 PM
1import { HttpBackend, HttpClient, HttpResponse } from '@angular/common/http';
2import { Inject, Injectable } from '@angular/core';
3import URLParse from 'url-parse';
4import { APPWRITE_LOCAL_STORAGE_PROVIDER_TOKEN, AppwriteOptions } from '../appwrite-angular.module';
5import { AppwriteException } from '../exceptions';
6import { APPWRITE_LOCATION_PROVIDER_TOKEN, APPWRITE_OPTIONS_TOKEN } from '../tokens';
7import { Headers, HttpMethods, Payload } from '../types';
8import { flatten } from '../util';
9
10@Injectable({ providedIn: 'root' })
11export class AppwriteService {
12 config = {
13 endpoint: 'https://appwrite.io/v1',
14 project: '',
15 jwt: '',
16 locale: '',
17 };
18 headers: Headers = {
19 'x-sdk-version': 'appwrite:web:3.2.0',
20 'X-Appwrite-Response-Format': '0.9.0',
21 };
22 private http: HttpClient;
23
24 constructor(
25 @Inject(APPWRITE_OPTIONS_TOKEN) config: AppwriteOptions['config'],
26 @Inject(APPWRITE_LOCAL_STORAGE_PROVIDER_TOKEN) public localStorageProvider,
27 @Inject(APPWRITE_LOCATION_PROVIDER_TOKEN) public locationProvider,
28 httpBackend: HttpBackend
29 ) {
30 this.http = new HttpClient(httpBackend);
31
32 if (!config || !config.endpointUrl || !config.endpointUrl) {
33 throw new Error('You are missing required config properties');
34 }
35 this.config.endpoint = config.endpointUrl;
36 this.config.project = config.projectId;
37 this.setEndpoint(config.endpointUrl).setProject(config.projectId);
38 }
39
40 setEndpoint(endpoint: string): this {
41 this.config.endpoint = endpoint;
42 return this;
43 }
44
45 setProject(value: string): this {
46 this.headers['X-Appwrite-Project'] = value;
47 this.config.project = value;
48 return this;
49 }
50
51 setJWT(value: string): this {
52 this.headers['X-Appwrite-JWT'] = value;
53 this.config.jwt = value;
54 return this;
55 }
56
57 setLocale(value: string): this {
58 this.headers['X-Appwrite-Locale'] = value;
59 this.config.locale = value;
60 return this;
61 }
62
63 public async call<T>(method: HttpMethods, path: string, headers: Headers = {}, params: Payload = {}): Promise<T> {
64 const url = new URLParse(this.config.endpoint + path);
65 method = method.toUpperCase() as HttpMethods;
66 headers = {
67 ...headers,
68 ...this.headers
69 };
70 const options: RequestInit = {
71 method,
72 headers,
73 credentials: 'include'
74 };
75 if (typeof this.localStorageProvider !== 'undefined' && this.localStorageProvider) {
76 headers['X-Fallback-Cookies'] = this.localStorageProvider.getItem('cookieFallback') ?? '';
77 }
78
79 if (method === 'GET') {
80 url.set('query', flatten(params));
81 } else {
82 switch (headers['content-type']) {
83 case 'application/json':
84 options.body = JSON.stringify(params);
85 break;
86
87 case 'multipart/form-data':
88 const formData = new FormData();
89
90 for (const key in params) {
91 if (Array.isArray(params[key])) {
92 formData.append(key + '[]', params[key].join(','));
93 } else {
94 formData.append(key, params[key]);
95 }
96 }
97
98 options.body = formData;
99 delete headers['content-type'];
100 break;
101 }
102 }
103
104 try {
105
106 const response: HttpResponse<T> = await this.http.request<T>(method, url.toString(), {
107 ...options,
108 headers: headers,
109 observe: 'response',
110 }).toPromise();
111 let data: any | { message: string } = null;
112 if (response.headers.get('content-type')?.includes('application/json')) {
113 data = response.body;
114 } else {
115 data = {
116 message: response.body
117 };
118 }
119 if (400 <= response.status) { throw new AppwriteException(data?.message, response.status, data); }
120
121 const cookieFallback = response.headers.get('X-Fallback-Cookies');
122
123 if (typeof this.localStorageProvider !== 'undefined' && this.localStorageProvider && cookieFallback) {
124 console.warn(
125 'Appwrite is using localStorage for session management. Increase your security by adding a custom domain as your API endpoint.');
126 this.localStorageProvider.setItem('cookieFallback', cookieFallback);
127 }
128
129 return data;
130 } catch (e) {
131 throw new AppwriteException(e.error.message || e.message);
132 }
133 }
134}
135