eli 0.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +146 -0
- data/lib/eli/admin/app.rb +322 -0
- data/lib/eli/admin/organization.rb +200 -0
- data/lib/eli/admin.rb +240 -0
- data/lib/eli/client.rb +259 -0
- data/lib/eli/config.rb +39 -0
- data/lib/eli/rest_api.rb +171 -0
- data/lib/eli/version.rb +5 -0
- data/lib/eli.rb +13 -0
- metadata +137 -0
data/lib/eli/admin.rb
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Eli
|
|
4
|
+
# Documentation for `Eli::Admin`.
|
|
5
|
+
#
|
|
6
|
+
# Administrative REST client used to manage admin sessions, accounts and to
|
|
7
|
+
# sign users in on their behalf.
|
|
8
|
+
module Admin
|
|
9
|
+
module_function
|
|
10
|
+
|
|
11
|
+
# Sign in.
|
|
12
|
+
#
|
|
13
|
+
# ## Examples
|
|
14
|
+
#
|
|
15
|
+
# Eli::Admin.sign_in("user.email@domain.com", "seCr#t.passw0rd")
|
|
16
|
+
# # 200
|
|
17
|
+
# # { "data" => { "token" => "JWT session token" } }
|
|
18
|
+
#
|
|
19
|
+
# # 400
|
|
20
|
+
# # { "errors" => { "detail" => "invalid credentials" } }
|
|
21
|
+
def sign_in(email, password)
|
|
22
|
+
url = Eli::Config.base_url + "/rest/admin/sessions"
|
|
23
|
+
|
|
24
|
+
options = {
|
|
25
|
+
params: {
|
|
26
|
+
email: email,
|
|
27
|
+
password: password
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
Eli::RestApi.post(url, options)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Checks whether the admin user is signed in or not.
|
|
35
|
+
#
|
|
36
|
+
# ## Examples
|
|
37
|
+
#
|
|
38
|
+
# Eli::Admin.signed_in("JWT session token")
|
|
39
|
+
# # true
|
|
40
|
+
# # false
|
|
41
|
+
def signed_in(session_token)
|
|
42
|
+
url = Eli::Config.base_url + "/rest/admin/sessions/signed_in"
|
|
43
|
+
|
|
44
|
+
options = {
|
|
45
|
+
headers: { "authorization" => "Bearer #{session_token}" }
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
resp = Eli::RestApi.head(url, options)
|
|
49
|
+
resp.status == 200
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Returns the current admin user data.
|
|
53
|
+
#
|
|
54
|
+
# ## Examples
|
|
55
|
+
#
|
|
56
|
+
# Eli::Admin.current_user("JWT session token")
|
|
57
|
+
# # 200
|
|
58
|
+
# # {
|
|
59
|
+
# # "data" => {
|
|
60
|
+
# # "active" => true,
|
|
61
|
+
# # "email" => "user@mail.com",
|
|
62
|
+
# # "id" => "732cf1c2-6299-41fa-8784-e458765743b7",
|
|
63
|
+
# # "language" => "en",
|
|
64
|
+
# # "name" => "User Name",
|
|
65
|
+
# # "timezone" => "Europe/London"
|
|
66
|
+
# # }
|
|
67
|
+
# # }
|
|
68
|
+
#
|
|
69
|
+
# # 404
|
|
70
|
+
# # { "errors" => { "detail" => "Not Found" } }
|
|
71
|
+
def current_user(session_token)
|
|
72
|
+
url = Eli::Config.base_url + "/rest/admin/sessions"
|
|
73
|
+
|
|
74
|
+
options = {
|
|
75
|
+
headers: { "authorization" => "Bearer #{session_token}" }
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
Eli::RestApi.get(url, options)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Refresh your token session returning a new session token.
|
|
82
|
+
#
|
|
83
|
+
# ## Examples
|
|
84
|
+
#
|
|
85
|
+
# Eli::Admin.refresh("JWT session token")
|
|
86
|
+
# # 200
|
|
87
|
+
# # { "data" => { "token" => "JWT session token" } }
|
|
88
|
+
#
|
|
89
|
+
# # 404
|
|
90
|
+
# # { "errors" => { "detail" => "Not Found" } }
|
|
91
|
+
def refresh(session_token)
|
|
92
|
+
url = Eli::Config.base_url + "/rest/admin/sessions"
|
|
93
|
+
|
|
94
|
+
options = {
|
|
95
|
+
headers: { "authorization" => "Bearer #{session_token}" }
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
Eli::RestApi.put(url, options)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Signs the admin user out closing and deleting the session.
|
|
102
|
+
#
|
|
103
|
+
# ## Examples
|
|
104
|
+
#
|
|
105
|
+
# Eli::Admin.sign_out("JWT session token")
|
|
106
|
+
# # 200
|
|
107
|
+
# # { "data" => { "message" => "signed out successfully" } }
|
|
108
|
+
#
|
|
109
|
+
# # 404
|
|
110
|
+
# # { "errors" => { "detail" => "Not Found" } }
|
|
111
|
+
def sign_out(session_token)
|
|
112
|
+
url = Eli::Config.base_url + "/rest/admin/sessions"
|
|
113
|
+
|
|
114
|
+
options = {
|
|
115
|
+
headers: { "authorization" => "Bearer #{session_token}" }
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
Eli::RestApi.delete(url, options)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Unlocks user making him/her able to sign in again.
|
|
122
|
+
#
|
|
123
|
+
# ## Examples
|
|
124
|
+
#
|
|
125
|
+
# Eli::Admin.unlock("Unlock token")
|
|
126
|
+
# # 202
|
|
127
|
+
# # { "data" => { "message" => "account was successfully unlocked" } }
|
|
128
|
+
#
|
|
129
|
+
# # 404
|
|
130
|
+
# # { "errors" => { "detail" => "Not Found" } }
|
|
131
|
+
def unlock(unlock_token)
|
|
132
|
+
url = Eli::Config.base_url + "/rest/accounts/unlock"
|
|
133
|
+
|
|
134
|
+
options = {
|
|
135
|
+
params: { token: unlock_token }
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
Eli::RestApi.put(url, options)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Confirms user's email.
|
|
142
|
+
#
|
|
143
|
+
# ## Examples
|
|
144
|
+
#
|
|
145
|
+
# Eli::Admin.confirm("Confirmation token")
|
|
146
|
+
# # 202
|
|
147
|
+
# # { "data" => { "message" => "account was successfully confirmed" } }
|
|
148
|
+
#
|
|
149
|
+
# # 404
|
|
150
|
+
# # { "errors" => { "detail" => "Not Found" } }
|
|
151
|
+
def confirm(confirmation_token)
|
|
152
|
+
url = Eli::Config.base_url + "/rest/accounts/confirm"
|
|
153
|
+
|
|
154
|
+
options = {
|
|
155
|
+
params: { token: confirmation_token }
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
Eli::RestApi.put(url, options)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Requests password recovery.
|
|
162
|
+
#
|
|
163
|
+
# ## Examples
|
|
164
|
+
#
|
|
165
|
+
# Eli::Admin.request_password_recovery("app token", "user@example.com")
|
|
166
|
+
# # 200
|
|
167
|
+
# # { "data" => { "message" => "password recovery was successfully requested" } }
|
|
168
|
+
#
|
|
169
|
+
# # 404
|
|
170
|
+
# # { "errors" => { "detail" => "Not Found" } }
|
|
171
|
+
def request_password_recovery(app_token, email)
|
|
172
|
+
url = Eli::Config.base_url + "/rest/accounts/password/recover"
|
|
173
|
+
|
|
174
|
+
options = {
|
|
175
|
+
headers: { "app-token" => app_token },
|
|
176
|
+
params: { email: email }
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
Eli::RestApi.post(url, options)
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Recover password updating it.
|
|
183
|
+
#
|
|
184
|
+
# ## Examples
|
|
185
|
+
#
|
|
186
|
+
# Eli::Admin.recover_password("token", "Secret.123", "Secret.123")
|
|
187
|
+
# # 200
|
|
188
|
+
# # { "data" => { "message" => "password was successfully recovered" } }
|
|
189
|
+
#
|
|
190
|
+
# # 400
|
|
191
|
+
# # { "errors" => { "detail" => "token is invalid" } }
|
|
192
|
+
#
|
|
193
|
+
# # 400
|
|
194
|
+
# # { "errors" => { "detail" => "password has an invalid format" } }
|
|
195
|
+
#
|
|
196
|
+
# # 400
|
|
197
|
+
# # { "errors" => { "detail" => "password and confirmation password are different" } }
|
|
198
|
+
def recover_password(token, password, password_confirmation)
|
|
199
|
+
url = Eli::Config.base_url + "/rest/accounts/password/recover"
|
|
200
|
+
|
|
201
|
+
options = {
|
|
202
|
+
params: {
|
|
203
|
+
token: token,
|
|
204
|
+
password: password,
|
|
205
|
+
password_confirmation: password_confirmation
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
Eli::RestApi.put(url, options)
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
# Admin signs in any user without password.
|
|
213
|
+
#
|
|
214
|
+
# ## Examples
|
|
215
|
+
#
|
|
216
|
+
# Eli::Admin.signs_in(
|
|
217
|
+
# "JWT session token",
|
|
218
|
+
# { email: "user.email@domain.com", name: "User Name" },
|
|
219
|
+
# "app_id"
|
|
220
|
+
# )
|
|
221
|
+
# # 200
|
|
222
|
+
# # { "data" => { "user" => { "active" => true, "email" => "..." } } }
|
|
223
|
+
#
|
|
224
|
+
# # 400
|
|
225
|
+
# # { "errors" => { "detail" => "invalid credentials" } }
|
|
226
|
+
def signs_in(session_token, user_data, app_id)
|
|
227
|
+
url = Eli::Config.base_url + "/rest/admin/sessions/signs_in"
|
|
228
|
+
|
|
229
|
+
options = {
|
|
230
|
+
headers: { "authorization" => "Bearer #{session_token}" },
|
|
231
|
+
params: {
|
|
232
|
+
user_data: user_data,
|
|
233
|
+
app_id: app_id
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
Eli::RestApi.post(url, options)
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
end
|
data/lib/eli/client.rb
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Documentation for `Eli`.
|
|
4
|
+
#
|
|
5
|
+
# Public REST client used by applications integrating with Letmein. These are
|
|
6
|
+
# the end-user facing endpoints (sessions and account management). The methods
|
|
7
|
+
# are available directly on the `Eli` module, e.g. `Eli.sign_in(...)`.
|
|
8
|
+
module Eli
|
|
9
|
+
module_function
|
|
10
|
+
|
|
11
|
+
# Sign in.
|
|
12
|
+
#
|
|
13
|
+
# ## Examples
|
|
14
|
+
#
|
|
15
|
+
# Eli.sign_in("app token", "user.email@domain.com", "secret.password")
|
|
16
|
+
# # 200
|
|
17
|
+
# # { "data" => { "token" => "JWT session token" } }
|
|
18
|
+
#
|
|
19
|
+
# # 400
|
|
20
|
+
# # { "errors" => { "detail" => "invalid credentials" } }
|
|
21
|
+
def sign_in(app_token, email, password)
|
|
22
|
+
url = Eli::Config.base_url + "/rest/sessions"
|
|
23
|
+
|
|
24
|
+
options = {
|
|
25
|
+
headers: { "app-token" => app_token },
|
|
26
|
+
params: {
|
|
27
|
+
email: email,
|
|
28
|
+
password: password
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
Eli::RestApi.post(url, options)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Checks whether the user is signed in or not.
|
|
36
|
+
#
|
|
37
|
+
# ## Examples
|
|
38
|
+
#
|
|
39
|
+
# Eli.signed_in("JWT session token")
|
|
40
|
+
# # true
|
|
41
|
+
# # false
|
|
42
|
+
def signed_in(session_token)
|
|
43
|
+
url = Eli::Config.base_url + "/rest/sessions/signed_in"
|
|
44
|
+
|
|
45
|
+
options = {
|
|
46
|
+
headers: { "authorization" => "Bearer #{session_token}" }
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
resp = Eli::RestApi.head(url, options)
|
|
50
|
+
resp.status == 200
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Returns the current user data.
|
|
54
|
+
#
|
|
55
|
+
# ## Examples
|
|
56
|
+
#
|
|
57
|
+
# Eli.current_user("JWT session token")
|
|
58
|
+
# # 200
|
|
59
|
+
# # {
|
|
60
|
+
# # "data" => {
|
|
61
|
+
# # "active" => true,
|
|
62
|
+
# # "email" => "user.name@domain.com",
|
|
63
|
+
# # "id" => "732cf1c2-6299-41fa-8784-e458765743b7",
|
|
64
|
+
# # "language" => "en",
|
|
65
|
+
# # "name" => "Adilson Chacon",
|
|
66
|
+
# # "timezone" => "Europe/London"
|
|
67
|
+
# # }
|
|
68
|
+
# # }
|
|
69
|
+
#
|
|
70
|
+
# # 404
|
|
71
|
+
# # { "errors" => { "detail" => "Not Found" } }
|
|
72
|
+
def current_user(session_token)
|
|
73
|
+
url = Eli::Config.base_url + "/rest/sessions"
|
|
74
|
+
|
|
75
|
+
options = {
|
|
76
|
+
headers: { "authorization" => "Bearer #{session_token}" }
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
Eli::RestApi.get(url, options)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Refresh your token session returning a new session token.
|
|
83
|
+
#
|
|
84
|
+
# ## Examples
|
|
85
|
+
#
|
|
86
|
+
# Eli.refresh("JWT session token")
|
|
87
|
+
# # 200
|
|
88
|
+
# # { "data" => { "token" => "JWT session token" } }
|
|
89
|
+
#
|
|
90
|
+
# # 404
|
|
91
|
+
# # { "errors" => { "detail" => "Not Found" } }
|
|
92
|
+
def refresh(session_token)
|
|
93
|
+
url = Eli::Config.base_url + "/rest/sessions"
|
|
94
|
+
|
|
95
|
+
options = {
|
|
96
|
+
headers: { "authorization" => "Bearer #{session_token}" }
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
Eli::RestApi.put(url, options)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Signs user out closing and deleting session.
|
|
103
|
+
#
|
|
104
|
+
# ## Examples
|
|
105
|
+
#
|
|
106
|
+
# Eli.sign_out("JWT session token")
|
|
107
|
+
# # 200
|
|
108
|
+
# # { "data" => { "message" => "signed out successfully" } }
|
|
109
|
+
#
|
|
110
|
+
# # 404
|
|
111
|
+
# # { "errors" => { "detail" => "Not Found" } }
|
|
112
|
+
def sign_out(session_token)
|
|
113
|
+
url = Eli::Config.base_url + "/rest/sessions"
|
|
114
|
+
|
|
115
|
+
options = {
|
|
116
|
+
headers: { "authorization" => "Bearer #{session_token}" }
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
Eli::RestApi.delete(url, options)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Unlocks user making him/her able to sign in again.
|
|
123
|
+
#
|
|
124
|
+
# ## Examples
|
|
125
|
+
#
|
|
126
|
+
# Eli.unlock("Unlock token")
|
|
127
|
+
# # 202
|
|
128
|
+
# # { "data" => { "message" => "account was successfully unlocked" } }
|
|
129
|
+
#
|
|
130
|
+
# # 404
|
|
131
|
+
# # { "errors" => { "detail" => "Not Found" } }
|
|
132
|
+
def unlock(unlock_token)
|
|
133
|
+
url = Eli::Config.base_url + "/rest/accounts/unlock"
|
|
134
|
+
|
|
135
|
+
options = {
|
|
136
|
+
params: { token: unlock_token }
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
Eli::RestApi.put(url, options)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Confirms user email.
|
|
143
|
+
#
|
|
144
|
+
# ## Examples
|
|
145
|
+
#
|
|
146
|
+
# Eli.confirm("Confirmation token")
|
|
147
|
+
# # 202
|
|
148
|
+
# # { "data" => { "message" => "account was successfully confirmed" } }
|
|
149
|
+
#
|
|
150
|
+
# # 404
|
|
151
|
+
# # { "errors" => { "detail" => "Not Found" } }
|
|
152
|
+
def confirm(confirmation_token)
|
|
153
|
+
url = Eli::Config.base_url + "/rest/accounts/confirm"
|
|
154
|
+
|
|
155
|
+
options = {
|
|
156
|
+
params: { token: confirmation_token }
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
Eli::RestApi.put(url, options)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# Requests password recovery.
|
|
163
|
+
#
|
|
164
|
+
# ## Examples
|
|
165
|
+
#
|
|
166
|
+
# Eli.request_password_recovery("app token", "user@example.com")
|
|
167
|
+
# # 200
|
|
168
|
+
# # { "data" => { "message" => "password recovery was successfully requested" } }
|
|
169
|
+
#
|
|
170
|
+
# # 404
|
|
171
|
+
# # { "errors" => { "detail" => "Not Found" } }
|
|
172
|
+
def request_password_recovery(app_token, email)
|
|
173
|
+
url = Eli::Config.base_url + "/rest/accounts/password/recover"
|
|
174
|
+
|
|
175
|
+
options = {
|
|
176
|
+
headers: { "app-token" => app_token },
|
|
177
|
+
params: { email: email }
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
Eli::RestApi.post(url, options)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Recover password updating it.
|
|
184
|
+
#
|
|
185
|
+
# ## Examples
|
|
186
|
+
#
|
|
187
|
+
# Eli.recover_password("token", "Secret.123", "Secret.123")
|
|
188
|
+
# # 200
|
|
189
|
+
# # { "data" => { "message" => "password was successfully recovered" } }
|
|
190
|
+
#
|
|
191
|
+
# # 400
|
|
192
|
+
# # { "errors" => { "detail" => "token is invalid" } }
|
|
193
|
+
#
|
|
194
|
+
# # 400
|
|
195
|
+
# # { "errors" => { "detail" => "password has an invalid format" } }
|
|
196
|
+
#
|
|
197
|
+
# # 400
|
|
198
|
+
# # { "errors" => { "detail" => "password and confirmation password are different" } }
|
|
199
|
+
def recover_password(token, password, password_confirmation)
|
|
200
|
+
url = Eli::Config.base_url + "/rest/accounts/password/recover"
|
|
201
|
+
|
|
202
|
+
options = {
|
|
203
|
+
params: {
|
|
204
|
+
token: token,
|
|
205
|
+
password: password,
|
|
206
|
+
password_confirmation: password_confirmation
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
Eli::RestApi.put(url, options)
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# Updates the password of the signed in user.
|
|
214
|
+
#
|
|
215
|
+
# ## Examples
|
|
216
|
+
#
|
|
217
|
+
# passwords = {
|
|
218
|
+
# current_password: "Secret.123",
|
|
219
|
+
# new_password: "NewSecret.1234",
|
|
220
|
+
# new_password_confirmation: "NewSecret.1234"
|
|
221
|
+
# }
|
|
222
|
+
# Eli.update_password("JWT session token", passwords)
|
|
223
|
+
# # 200
|
|
224
|
+
# # { "data" => { "message" => "password was successfully changed" } }
|
|
225
|
+
#
|
|
226
|
+
# # 400 or 404
|
|
227
|
+
# # { "errors" => { "detail" => "Error message" } }
|
|
228
|
+
def update_password(session_token, passwords)
|
|
229
|
+
url = Eli::Config.base_url + "/rest/accounts/password/update"
|
|
230
|
+
|
|
231
|
+
options = {
|
|
232
|
+
headers: { "authorization" => "Bearer #{session_token}" },
|
|
233
|
+
params: passwords
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
Eli::RestApi.put(url, options)
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# Resend email for account confirmation.
|
|
240
|
+
#
|
|
241
|
+
# ## Examples
|
|
242
|
+
#
|
|
243
|
+
# Eli.resend_account_confirmation_email("App token", "user@example.com")
|
|
244
|
+
# # 200
|
|
245
|
+
# # { "data" => { "message" => "account confirmation email was successfully sent" } }
|
|
246
|
+
#
|
|
247
|
+
# # 404
|
|
248
|
+
# # { "errors" => { "detail" => "Not Found" } }
|
|
249
|
+
def resend_account_confirmation_email(app_token, email)
|
|
250
|
+
url = Eli::Config.base_url + "/rest/accounts/confirm/resend"
|
|
251
|
+
|
|
252
|
+
options = {
|
|
253
|
+
headers: { "app-token" => app_token },
|
|
254
|
+
params: { email: email }
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
Eli::RestApi.post(url, options)
|
|
258
|
+
end
|
|
259
|
+
end
|
data/lib/eli/config.rb
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Eli
|
|
4
|
+
# Documentation for `Eli::Config`.
|
|
5
|
+
#
|
|
6
|
+
# Holds the configuration used by the library, the most important being the
|
|
7
|
+
# base URL of the Letmein server the client talks to.
|
|
8
|
+
class Config
|
|
9
|
+
DEFAULT_BASE_URL = "http://localhost:4000"
|
|
10
|
+
|
|
11
|
+
class << self
|
|
12
|
+
# Set base_url value.
|
|
13
|
+
#
|
|
14
|
+
# ### Example
|
|
15
|
+
# Eli::Config.base_url = "http://localhost:4000"
|
|
16
|
+
def base_url=(value)
|
|
17
|
+
raise ArgumentError, "base_url must be a string" unless value.is_a?(String)
|
|
18
|
+
|
|
19
|
+
@base_url = value
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Get base_url value.
|
|
23
|
+
#
|
|
24
|
+
# Falls back to the `LETMEIN_BASE_URL` environment variable and finally to
|
|
25
|
+
# `DEFAULT_BASE_URL` when nothing was explicitly configured.
|
|
26
|
+
#
|
|
27
|
+
# ### Example
|
|
28
|
+
# Eli::Config.base_url
|
|
29
|
+
def base_url
|
|
30
|
+
@base_url || ENV["LETMEIN_BASE_URL"] || DEFAULT_BASE_URL
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Resets any value set through `base_url=` (useful for tests).
|
|
34
|
+
def reset!
|
|
35
|
+
@base_url = nil
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
data/lib/eli/rest_api.rb
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "uri"
|
|
5
|
+
require "faraday"
|
|
6
|
+
|
|
7
|
+
module Eli
|
|
8
|
+
# Documentation for `Eli::RestApi`.
|
|
9
|
+
#
|
|
10
|
+
# Thin wrapper around Faraday that mirrors the behaviour of the Elixir `Req`
|
|
11
|
+
# based client: it normalizes headers (always sending a JSON content type),
|
|
12
|
+
# encodes request bodies as JSON and appends params to the query string for
|
|
13
|
+
# the verbs that don't carry a body.
|
|
14
|
+
class RestApi
|
|
15
|
+
JSON_CONTENT_TYPE = "application/json"
|
|
16
|
+
|
|
17
|
+
# Lightweight response value object exposing `status` and the parsed `body`.
|
|
18
|
+
Response = Struct.new(:status, :body)
|
|
19
|
+
|
|
20
|
+
class << self
|
|
21
|
+
# Post.
|
|
22
|
+
#
|
|
23
|
+
# ## Examples
|
|
24
|
+
#
|
|
25
|
+
# Eli::RestApi.post("/rest/your/endpoint", params: { foo: "bar" }, headers: { "token" => "A_TOKEN" })
|
|
26
|
+
def post(url, options = {})
|
|
27
|
+
request_with_body(:post, url, options)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Put.
|
|
31
|
+
#
|
|
32
|
+
# ## Examples
|
|
33
|
+
#
|
|
34
|
+
# Eli::RestApi.put("/rest/your/endpoint", params: { foo: "bar" }, headers: { "token" => "A_TOKEN" })
|
|
35
|
+
def put(url, options = {})
|
|
36
|
+
request_with_body(:put, url, options)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Patch.
|
|
40
|
+
#
|
|
41
|
+
# ## Examples
|
|
42
|
+
#
|
|
43
|
+
# Eli::RestApi.patch("/rest/your/endpoint", params: { foo: "bar" }, headers: { "token" => "A_TOKEN" })
|
|
44
|
+
def patch(url, options = {})
|
|
45
|
+
request_with_body(:patch, url, options)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Get.
|
|
49
|
+
#
|
|
50
|
+
# ## Examples
|
|
51
|
+
#
|
|
52
|
+
# Eli::RestApi.get("/rest/your/endpoint", params: { foo: "bar" }, headers: { "token" => "A_TOKEN" })
|
|
53
|
+
def get(url, options = {})
|
|
54
|
+
request_with_query(:get, url, options)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Head.
|
|
58
|
+
#
|
|
59
|
+
# ## Examples
|
|
60
|
+
#
|
|
61
|
+
# Eli::RestApi.head("/rest/your/endpoint", params: { foo: "bar" }, headers: { "token" => "A_TOKEN" })
|
|
62
|
+
def head(url, options = {})
|
|
63
|
+
request_with_query(:head, url, options)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Delete.
|
|
67
|
+
#
|
|
68
|
+
# ## Examples
|
|
69
|
+
#
|
|
70
|
+
# Eli::RestApi.delete("/rest/your/endpoint", params: { foo: "bar" }, headers: { "token" => "A_TOKEN" })
|
|
71
|
+
def delete(url, options = {})
|
|
72
|
+
request_with_query(:delete, url, options)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
private
|
|
76
|
+
|
|
77
|
+
def request_with_body(method, url, options)
|
|
78
|
+
response = connection.run_request(
|
|
79
|
+
method,
|
|
80
|
+
url,
|
|
81
|
+
JSON.generate(options[:params] || {}),
|
|
82
|
+
normalize_headers(options[:headers])
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
build_response(response)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def request_with_query(method, url, options)
|
|
89
|
+
response = connection.run_request(
|
|
90
|
+
method,
|
|
91
|
+
build_url(url, options[:params]),
|
|
92
|
+
nil,
|
|
93
|
+
normalize_headers(options[:headers])
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
build_response(response)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def connection
|
|
100
|
+
Faraday.new
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def build_response(response)
|
|
104
|
+
Response.new(response.status, parse_body(response.body))
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def parse_body(body)
|
|
108
|
+
return body if body.nil? || body.to_s.empty?
|
|
109
|
+
|
|
110
|
+
JSON.parse(body)
|
|
111
|
+
rescue JSON::ParserError
|
|
112
|
+
body
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def normalize_headers(headers)
|
|
116
|
+
headers = build_headers(headers)
|
|
117
|
+
|
|
118
|
+
if app_json_content_type?(headers)
|
|
119
|
+
headers
|
|
120
|
+
else
|
|
121
|
+
headers.merge(default_headers)
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def build_headers(headers)
|
|
126
|
+
case headers
|
|
127
|
+
when nil
|
|
128
|
+
default_headers
|
|
129
|
+
when Hash
|
|
130
|
+
stringify(headers)
|
|
131
|
+
when Array
|
|
132
|
+
stringify(headers.to_h)
|
|
133
|
+
else
|
|
134
|
+
raise ArgumentError, "headers must be a Hash, an Array of pairs or nil"
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def default_headers
|
|
139
|
+
{ "content-type" => JSON_CONTENT_TYPE }
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def stringify(headers)
|
|
143
|
+
headers.each_with_object({}) do |(key, value), acc|
|
|
144
|
+
acc[key.to_s] = value.to_s
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def app_json_content_type?(headers)
|
|
149
|
+
headers.any? do |key, value|
|
|
150
|
+
key.to_s.upcase == "CONTENT-TYPE" && value.to_s.upcase == JSON_CONTENT_TYPE.upcase
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def build_url(url, params)
|
|
155
|
+
return url if params.nil? || params.empty?
|
|
156
|
+
|
|
157
|
+
uri = URI.parse(url)
|
|
158
|
+
existing = uri.query ? URI.decode_www_form(uri.query).to_h : {}
|
|
159
|
+
merged = existing.merge(stringify_params(params))
|
|
160
|
+
uri.query = URI.encode_www_form(merged)
|
|
161
|
+
uri.to_s
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def stringify_params(params)
|
|
165
|
+
params.each_with_object({}) do |(key, value), acc|
|
|
166
|
+
acc[key.to_s] = value.to_s
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|