はじめに

NativeScript の API Client のサンプル。

axios/axiosNativeScript/nativescript-background-http とを使って実装。

あくまでも一例なので、各自の環境に合わせて適宜修正。

※試してないが 、今からなら klippa-app/nativescript-http を使うのが良いかもしれない。(最近(2020/03/22 以降) リリースされているので、API Client 作った時には無かった)

TL;DR

目次

  1. はじめに
  2. TL;DR
  3. 環境・条件
  4. 詳細
    1. API Client 実装例
    2. 使い方
  5. まとめ
  6. その他・メモ
  7. 参考文献

環境・条件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.15.4
BuildVersion: 19E287

$ node -v
v12.7.0

$ npm -v
6.10.3

$ tns --version
6.4.0

$ grep -C1 version package.json
"tns-android": {
"version": "6.0.0"
},
"tns-ios": {
"version": "6.4.2"
}

$ tns plugin
Dependencies:
┌──────────────────────────────┬─────────┐
│ Plugin │ Version │
│ @nativescript/theme │ ^2.2.1 │
│ @vue/devtools │ ^5.0.6 │
│ axios │ ^0.19.2 │
│ jsbarcode │ ^3.11.0 │
│ nativescript-background-http │ ^4.2.1 │
│ nativescript-socketio │ ^3.2.1 │
│ nativescript-toasty │ ^1.3.0 │
│ nativescript-vue │ ^2.4.0 │
│ nativescript-vue-devtools │ ^1.2.0 │
│ tns-core-modules │ ^6.0.0 │
└──────────────────────────────┴─────────┘
Dev Dependencies:
┌────────────────────────────────────┬─────────┐
│ Plugin │ Version │
│ @babel/core │ ^7.0.0 │
│ @babel/preset-env │ ^7.0.0 │
│ babel-loader │ ^8.0.2 │
│ nativescript-dev-webpack │ ^1.0.0 │
│ nativescript-vue-template-compiler │ ^2.0.0 │
│ nativescript-worker-loader │ ~0.9.0 │
│ node-sass │ ^4.9.2 │
│ vue-loader │ ^15.4.0 │
└────────────────────────────────────┴─────────┘

詳細

API Client 実装例

NativeScript-Vue での実装例、app/mixins/ApiClient.js として実装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import axios from 'axios';
import * as bgHttp from 'nativescript-background-http';
import * as mime from 'mime-types';

export default {
data() {
return {
apiBase: 'https://path/to/api',
}
},
methods: {
async requestBgHttp(url, method, params = null, config = null) {
let request = {
url,
method,
headers: {
'Content-Type': 'application/octet-stream',
},
description: 'Request with files',
};
if (config) {
Object.assign(request, config);
}

let session, task;
if (params.file) {
// 引数('image-upload' の部分) は Session ID として利用される
// (※複数セッションを同時に使わない限りは気にしなくて良さそう)
session = bgHttp.session(`upload: ${Math.random()}`);
request.headers['File-Name'] = params.file.name;
// ファイル単体の場合は uploadFile を使う
task = session.uploadFile(params.file.path, request);
} else {
session = bgHttp.session(`multipart: ${Math.random()}`);
const _params = Object.entries(params).map(e => {
if (typeof e[1] === 'object' && e[1].file) {
return {
name: e[0],
filename: e[1].file.path,
mimeType: mime.lookup(e[1].file.path),
};
} else {
return { name: e[0], value: e[1] };
}
});
// 他データも含む場合は multipartUpload を使う
task = session.multipartUpload(_params, request);
}

const taskPromise = new Promise((resolve, reject) => {
task.on('progress', e => console.log({ e }));
task.on('responded', e => resolve(e));
task.on('complete', e => resolve(e));
task.on('cancelled', e => resolve(e));
task.on('error', e => reject(e));
});

const res = await Promise.resolve(taskPromise)
.catch(error => {
console.error({error});
throw error;
});

switch (res.eventName) {
case 'responded':
case 'complete':
case 'cancelled':
return res;

default:
break;
}
return res;
},
async requestAxios(url, method, params = null, config = null) {
let options = { url, method };
if (params) {
if (method === 'GET') {
options.params = params;
} else {
options.data = params;
}
}
if (config) {
Object.assign(options, config);
}
try {
const res = await axios.request(options);
console.log({res});
return res;
} catch (error) {
console.error({
error,
request: error.request,
response: error.response,
config: error.config,
message: error.message,
});
throw error;
}
},
async request(url, method, params = null, hasFile = false, config = null) {
if (hasFile) {
return await this.requestBgHttp(url, method, params, config);
} else {
return await this.requestAxios(url, method, params, config);
}
},
async get(path, params = null, config = null) {
return await this.request(`${this.apiBase}/${path}`, 'GET', params, false, config);
},
async post(path, params, hasFile=false, config = null) {
return await this.request(`${this.apiBase}/${path}`, 'POST', params, hasFile, config);
},
async put(path, params, hasFile=false, config = null) {
return await this.request(`${this.apiBase}/${path}`, 'PUT', params, hasFile, config);
},
async patch(path, params, hasFile=false, config = null) {
return await this.request(`${this.apiBase}/${path}`, 'PATCH', params, hasFile, config);
},
async delete(path, params, config = null) {
return await this.request(`${this.apiBase}/${path}`, 'DELETE', params, false, config);
},
},
}

使い方

NativeScript-Vue での使用例

app/main.js

1
2
3
4
5
6
7
8
9
10
11
import Vue from 'nativescript-vue'

// mixin として設定
import ApiClient from './mixins/ApiClient'
Vue.mixin(ApiClient);

import App from './components/App'
new Vue({
store,
render: h => h('frame', [h(App)])
}).$start()

app/components/App.vue などで、以下のように使っても良いし、

1
2
3
4
5
6
7
8
9
10
11
12
13
<script >
export default {
methods: {
async get_users() {
const res = await this.get('users');
},
async post_news() {
const params = { title: 'hello' };
const res = await this.post('news', params);
},
},
}
</script>

app/mixins/ApiClient.js に以下のように追加して、xxxx.vue でそっちを実行するでも良い。
(ApiClient.js ではなく ApiClientBase.js としておいて、ApiClient.js は別途実装でも良いと思う)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
export default {
...,
methods: {
...,
async delete(path, params, config = null) {
return await this.request(`${this.apiBase}/${path}`, 'DELETE', params, false, config);
},
async get_users() {
return await this.get('users');
},
async post_news(title) {
const params = { title };
return await this.post('news', params);
},
...,
},
}

まとめ

その他・メモ

冒頭にも書いたが、klippa-app/nativescript-http を試してみるのもあり。

参考文献

関連記事