amazon-chime-sdk-rails 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/build.yml +69 -0
  3. data/.gitignore +7 -1
  4. data/CHANGELOG.md +19 -0
  5. data/Dockerfile +15 -0
  6. data/Gemfile +5 -3
  7. data/README.md +132 -1005
  8. data/docs/Develop_Rails_API_Application.md +569 -0
  9. data/docs/Develop_Rails_View_Application.md +441 -0
  10. data/gemfiles/Gemfile.rails-5.0 +1 -1
  11. data/gemfiles/Gemfile.rails-5.1 +0 -1
  12. data/gemfiles/Gemfile.rails-5.2 +0 -1
  13. data/gemfiles/Gemfile.rails-6.0 +0 -1
  14. data/gemfiles/Gemfile.rails-6.1 +24 -0
  15. data/gemfiles/Gemfile.rails-7.0 +30 -0
  16. data/lib/chime_sdk/controller/meetings.rb +4 -3
  17. data/lib/chime_sdk/version.rb +1 -1
  18. data/lib/generators/chime_sdk/js_generator.rb +72 -9
  19. data/lib/generators/templates/controllers/meetings_controller.rb +1 -1
  20. data/spec/generators/js_generator_spec.rb +66 -6
  21. data/spec/rails_app/app/assets/config/manifest.js +1 -0
  22. data/spec/rails_app/app/assets/javascripts/application.js +3 -0
  23. data/spec/rails_app/app/controllers/api/public/meeting_attendees_controller.rb +11 -0
  24. data/spec/rails_app/app/controllers/api/public/meetings_controller.rb +15 -0
  25. data/spec/rails_app/app/controllers/meetings_controller.rb +1 -1
  26. data/spec/rails_app/app/views/layouts/_header.html.erb +1 -5
  27. data/spec/rails_app/app/views/layouts/application.html.erb +1 -2
  28. data/spec/rails_app/app/views/meetings/show.html.erb +22 -2
  29. data/spec/rails_app/config/application.rb +11 -2
  30. data/spec/rails_app/config/initializers/devise_token_auth.rb +1 -1
  31. data/spec/rails_app/config/routes.rb +10 -3
  32. data/spec/rails_app/db/seeds.rb +1 -1
  33. data/spec/requests/meetings_spec.rb +1 -1
  34. data/templates/amazon-chime-sdk-policy.yml +49 -0
  35. metadata +19 -57
  36. data/.travis.yml +0 -47
  37. data/spec/rails_app/app/controllers/spa_controller.rb +0 -6
  38. data/spec/rails_app/app/javascript/App.vue +0 -50
  39. data/spec/rails_app/app/javascript/channels/consumer.js +0 -6
  40. data/spec/rails_app/app/javascript/channels/index.js +0 -5
  41. data/spec/rails_app/app/javascript/components/DeviseTokenAuth.vue +0 -84
  42. data/spec/rails_app/app/javascript/components/meetings/Index.vue +0 -100
  43. data/spec/rails_app/app/javascript/components/meetings/Meeting.vue +0 -178
  44. data/spec/rails_app/app/javascript/components/rooms/Index.vue +0 -53
  45. data/spec/rails_app/app/javascript/components/rooms/Show.vue +0 -91
  46. data/spec/rails_app/app/javascript/packs/application.js +0 -17
  47. data/spec/rails_app/app/javascript/packs/spa.js +0 -14
  48. data/spec/rails_app/app/javascript/router/index.js +0 -74
  49. data/spec/rails_app/app/javascript/store/index.js +0 -37
  50. data/spec/rails_app/app/views/spa/index.html.erb +0 -1
  51. data/spec/rails_app/babel.config.js +0 -72
  52. data/spec/rails_app/bin/webpack +0 -18
  53. data/spec/rails_app/bin/webpack-dev-server +0 -18
  54. data/spec/rails_app/config/webpack/development.js +0 -5
  55. data/spec/rails_app/config/webpack/environment.js +0 -7
  56. data/spec/rails_app/config/webpack/loaders/vue.js +0 -6
  57. data/spec/rails_app/config/webpack/production.js +0 -5
  58. data/spec/rails_app/config/webpack/test.js +0 -5
  59. data/spec/rails_app/config/webpacker.yml +0 -97
  60. data/spec/rails_app/package.json +0 -23
  61. data/spec/rails_app/postcss.config.js +0 -12
@@ -0,0 +1,569 @@
1
+ ## Develop your Rails API Application
2
+
3
+ Let's start to build simple Rails API application providing real-time communications in a private room.
4
+ For example, create Rails API application using [Devise Token Auth](https://github.com/lynndylanhurley/devise_token_auth) for user authentication.
5
+
6
+ ### Prepare Rails API application
7
+
8
+ At first, create new Rails application:
9
+
10
+ ```bash
11
+ $ rails new chime_api_app --api
12
+ $ cd chime_api_app
13
+ ```
14
+
15
+ Add gems to your Gemfile:
16
+
17
+ ```ruby:Gemfile
18
+ # Gemfile
19
+
20
+ gem 'devise_token_auth'
21
+ gem 'amazon-chime-sdk-rails'
22
+ ```
23
+
24
+ Then, install *devise_token_auth*:
25
+
26
+ ```bash
27
+ $ bundle install
28
+ $ rails g devise:install
29
+ $ rails g devise_token_auth:install User auth
30
+ ```
31
+
32
+ Update your `application_controller.rb` like this:
33
+
34
+ ```ruby:app/controllers/application_controller.rb
35
+ # app/controllers/application_controller.rb
36
+
37
+ class ApplicationController < ActionController::API
38
+ include ActionController::Helpers
39
+ include DeviseTokenAuth::Concerns::SetUserByToken
40
+ before_action :configure_permitted_parameters, if: :devise_controller?
41
+
42
+ protected
43
+ def configure_permitted_parameters
44
+ devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
45
+ end
46
+ end
47
+ ```
48
+
49
+ Update your `user.rb` to remove unnecessary options like this:
50
+
51
+ ```ruby:app/models/user.rb
52
+ # app/models/user.rb
53
+
54
+ class User < ActiveRecord::Base
55
+ devise :database_authenticatable, :registerable
56
+ include DeviseTokenAuth::Concerns::User
57
+ end
58
+ ```
59
+
60
+ Update *devise_token_auth* configuration in `devise_token_auth.rb` to keep authorization headers:
61
+
62
+ ```ruby:config/initializers/devise_token_auth.rb
63
+ # config/initializers/devise_token_auth.rb
64
+
65
+ DeviseTokenAuth.setup do |config|
66
+ # Uncomment and update
67
+ config.change_headers_on_each_request = false
68
+ end
69
+ ```
70
+
71
+ ### Create private room functions
72
+
73
+ Create models and controllers by generator:
74
+
75
+ ```bash
76
+ $ rails g model room name:string
77
+ $ rails g scaffold_controller api/rooms name:string --model-name=room
78
+ $ rails g model entry room:references user:references
79
+ $ rails g scaffold_controller api/entries room:references user:references --model-name=entry
80
+ $ rake db:migrate
81
+ ```
82
+
83
+ Update your `room.rb` like this:
84
+
85
+ ```ruby:app/models/room.rb
86
+ # app/models/room.rb
87
+
88
+ class Room < ApplicationRecord
89
+ has_many :entries, dependent: :destroy
90
+ has_many :members, through: :entries, source: :user
91
+
92
+ def member?(user)
93
+ members.include?(user)
94
+ end
95
+
96
+ def as_json(options = {})
97
+ super options.merge(:methods => [:members])
98
+ end
99
+ end
100
+ ```
101
+
102
+ Add uniqueness validation to your `entry.rb` like this:
103
+
104
+ ```ruby:app/models/entry.rb
105
+ # app/models/entry.rb
106
+
107
+ class Entry < ApplicationRecord
108
+ belongs_to :room
109
+ belongs_to :user
110
+ # Add uniqueness validation
111
+ validates :user, uniqueness: { scope: :room }
112
+ end
113
+ ```
114
+
115
+ Remove location header from your `rooms_controller.rb` and `entries_controller.rb` like this:
116
+
117
+ ```ruby:app/controllers/api/rooms_controller.rb
118
+ # app/controllers/api/rooms_controller.rb
119
+
120
+ # POST /rooms
121
+ def create
122
+ @room = Room.new(room_params)
123
+
124
+ if @room.save
125
+ render json: @room, status: :created # Remove location header
126
+ else
127
+ render json: @room.errors, status: :unprocessable_entity
128
+ end
129
+ end
130
+ ```
131
+
132
+ ```ruby:app/controllers/api/entries_controller.rb
133
+ # app/controllers/api/entries_controller.rb
134
+
135
+ # POST /entries
136
+ def create
137
+ @entry = Entry.new(entry_params)
138
+
139
+ if @entry.save
140
+ render json: @entry, status: :created # Remove location header
141
+ else
142
+ render json: @entry.errors, status: :unprocessable_entity
143
+ end
144
+ end
145
+ ```
146
+
147
+ ### Develop meeting functions with amazon-chime-sdk-rails
148
+
149
+ Install *amazon-chime-sdk-rails* and generate your controllers by *Controller Generator*:
150
+
151
+ ```bash
152
+ $ rails g chime_sdk:install
153
+ $ rails g chime_sdk:controllers -r room -n api
154
+ ```
155
+
156
+ Add and uncomment several functions in generated `meetings_controller.rb` and `meeting_attendees_controller.rb` for your app configurations:
157
+
158
+ ```ruby:app/controllers/api/meetings_controller.rb
159
+ # app/controllers/api/meetings_controller.rb
160
+
161
+ class Api::MeetingsController < ApplicationController
162
+ before_action :authenticate_api_user!
163
+ include DeviseTokenAuth::Concerns::SetUserByToken
164
+ before_action :set_room
165
+ before_action :check_membership
166
+
167
+ include ChimeSdk::Controller::Meetings::Mixin
168
+
169
+ private
170
+ # Add
171
+ def set_room
172
+ @room = Room.find(params[:room_id])
173
+ end
174
+
175
+ # Add
176
+ def check_membership
177
+ unless @room.member?(current_api_user)
178
+ message = 'Unauthorized: you are not a member of this private room.'
179
+ render json: { room: @room, notice: message }, status: :forbidden
180
+ end
181
+ end
182
+
183
+ # Uncomment
184
+ def meeting_request_id
185
+ "PrivateRoom-#{@room.id}"
186
+ end
187
+
188
+ # Uncomment and update
189
+ def attendee_request_id
190
+ "User-#{current_api_user.id}"
191
+ end
192
+
193
+ # Uncomment
194
+ def application_meeting_metadata(meeting)
195
+ {
196
+ "MeetingType": "PrivateRoom",
197
+ "PrivateRoom": @room
198
+ }
199
+ end
200
+
201
+ # Uncomment
202
+ def application_attendee_metadata(attendee)
203
+ user_id = attendee[:Attendee][:ExternalUserId].split('-')[3]
204
+ {
205
+ "AttendeeType": "User",
206
+ "User": User.find_by_id(user_id)
207
+ }
208
+ end
209
+ end
210
+ ```
211
+
212
+ ```ruby:app/controllers/api/meeting_attendees_controller.rb
213
+ # app/controllers/api/meeting_attendees_controller.rb
214
+
215
+ class Api::MeetingAttendeesController < ApplicationController
216
+ before_action :authenticate_api_user!
217
+ include DeviseTokenAuth::Concerns::SetUserByToken
218
+ before_action :set_room
219
+ before_action :check_membership
220
+
221
+ include ChimeSdk::Controller::Attendees::Mixin
222
+
223
+ private
224
+ # Add
225
+ def set_room
226
+ @room = Room.find(params[:room_id])
227
+ end
228
+
229
+ # Add
230
+ def check_membership
231
+ unless @room.member?(current_api_user)
232
+ message = 'Unauthorized: you are not a member of this private room.'
233
+ render json: { room: @room, notice: message }, status: :forbidden
234
+ end
235
+ end
236
+
237
+ # Uncomment and update
238
+ def attendee_request_id
239
+ "User-#{current_api_user.id}"
240
+ end
241
+
242
+ # Uncomment
243
+ def application_attendee_metadata(attendee)
244
+ user_id = attendee[:Attendee][:ExternalUserId].split('-')[3]
245
+ {
246
+ "AttendeeType": "User",
247
+ "User": User.find_by_id(user_id)
248
+ }
249
+ end
250
+ end
251
+ ```
252
+
253
+ Then, update your `routes.rb` like this:
254
+
255
+ ```ruby:config/routes.rb
256
+ # config/routes.rb
257
+
258
+ Rails.application.routes.draw do
259
+ namespace :api do
260
+ scope :"v1" do
261
+ mount_devise_token_auth_for 'User', at: 'auth'
262
+ resources :rooms do
263
+ resources :entries, only: [:create, :destroy]
264
+ resources :meetings, defaults: { format: :json }, only: [:index, :show, :create, :destroy] do
265
+ resources :meeting_attendees, as: :attendees, path: :attendees, only: [:index, :show, :create, :destroy]
266
+ end
267
+ end
268
+ end
269
+ end
270
+ end
271
+ ```
272
+
273
+ Note that you need to set up AWS credentials or IAM role for *amazon-chime-sdk-rails*. See [Set up AWS credentials](#set-up-aws-credentials) for more details.
274
+
275
+ Finally, start rails server:
276
+
277
+ ```bash
278
+ $ rails s
279
+ ```
280
+
281
+ Now ready to take off!
282
+
283
+ ### Get meeting configurations through Rails API
284
+
285
+ Created Rails API works like this:
286
+
287
+ ```bash
288
+ # Sign up users
289
+
290
+ $ curl localhost:3000/api/v1/auth -X POST -H "content-type:application/json" -d '{"email":"ichiro@example.com", "password":"password", "password_confirmation":"password", "name":"ichiro"}'
291
+
292
+ {"status":"success","data":{"id":1,"provider":"email","uid":"ichiro@example.com","allow_password_change":false,"name":"ichiro","nickname":null,"image":null,"email":"ichiro@example.com","created_at":"2020-10-16T11:14:48.731Z","updated_at":"2020-10-16T11:14:48.827Z"}}
293
+
294
+ $ curl localhost:3000/api/v1/auth -X POST -H "content-type:application/json" -d '{"email":"stephen@example.com", "password":"password", "password_confirmation":"password", "name":"stephen"}'
295
+
296
+ {"status":"success","data":{"id":2,"provider":"email","uid":"stephen@example.com","allow_password_change":false,"name":"stephen","nickname":null,"image":null,"email":"stephen@example.com","created_at":"2020-10-16T11:15:33.226Z","updated_at":"2020-10-16T11:15:33.314Z"}}
297
+
298
+ # Create private room
299
+
300
+ $ curl localhost:3000/api/v1/rooms -X POST -H "content-type:application/json" -d '{"room":{"name":"PrivateRoom-1"}}'
301
+
302
+ {"id":1,"name":"PrivateRoom-1","created_at":"2020-10-16T11:15:56.223Z","updated_at":"2020-10-16T11:15:56.223Z","members":[]}
303
+
304
+ # You cannot create meeting yet because the user is not signed in
305
+
306
+ $ curl localhost:3000/api/v1/rooms/3/meetings -X POST -H "content-type:application/json"
307
+
308
+ {"errors":["You need to sign in or sign up before continuing."]}
309
+
310
+ # Sign in as ichiro
311
+
312
+ $ curl localhost:3000/api/v1/auth/sign_in -X POST -H "content-type:application/json" -D auth_headers.txt -d '{"email":"ichiro@example.com", "password":"password"}'
313
+
314
+ {"data":{"id":1,"email":"ichiro@example.com","provider":"email","uid":"ichiro@example.com","allow_password_change":false,"name":"ichiro","nickname":null,"image":null}}
315
+
316
+ $ _ACCESS_TOKEN=$(cat auth_headers.txt | grep access-token | rev | cut -c 2- | rev)
317
+ $ _CLIENT=$(cat auth_headers.txt | grep client | rev | cut -c 2- | rev)
318
+ $ _UID=$(cat auth_headers.txt | grep uid | rev | cut -c 2- | rev)
319
+
320
+ # You cannot create meeting yet because the user is not a member of the private room
321
+
322
+ $ curl localhost:3000/api/v1/rooms/1/meetings -X POST -H "content-type:application/json" -H "${_ACCESS_TOKEN}" -H "${_CLIENT}" -H "${_UID}"
323
+
324
+ {"room":{"id":1,"name":"PrivateRoom-1","created_at":"2020-10-16T11:15:56.223Z","updated_at":"2020-10-16T11:15:56.223Z","members":[]},"notice":"Unauthorized: you are not a member of this private room."}
325
+
326
+ # Add users to the private room
327
+
328
+ $ curl localhost:3000/api/v1/rooms/1/entries -X POST -H "content-type:application/json" -d '{"entry":{"room_id":1,"user_id":1}}'
329
+
330
+ {"id":1,"room_id":1,"user_id":1,"created_at":"2020-10-16T11:18:22.839Z","updated_at":"2020-10-16T11:18:22.839Z"}
331
+
332
+ $ curl localhost:3000/api/v1/rooms/1/entries -X POST -H "content-type:application/json" -d '{"entry":{"room_id":1,"user_id":2}}'
333
+
334
+ {"id":2,"room_id":1,"user_id":2,"created_at":"2020-10-16T11:18:41.116Z","updated_at":"2020-10-16T11:18:41.116Z"}
335
+
336
+ # Now you can create meeting as a member of the private room
337
+
338
+ $ curl localhost:3000/api/v1/rooms/1/meetings -X POST -H "content-type:application/json" -H "${_ACCESS_TOKEN}" -H "${_CLIENT}" -H "${_UID}" | jq .
339
+
340
+ {
341
+ "Meeting": {
342
+ "MeetingId": "2f550432-579c-4058-bbb9-XXXXXXXXXXXX",
343
+ "ExternalMeetingId": "ChimeSdkRailsApp-development-PrivateRoom-1",
344
+ "MediaPlacement": {
345
+ "AudioHostUrl": "d3175d855e633b72aedbXXXXXXXXXXXX.k.m2.ue1.app.chime.aws:3478",
346
+ "AudioFallbackUrl": "wss://haxrp.m2.ue1.app.chime.aws:443/calls/2f550432-579c-4058-bbb9-XXXXXXXXXXXX",
347
+ "ScreenDataUrl": "wss://bitpw.m2.ue1.app.chime.aws:443/v2/screen/2f550432-579c-4058-bbb9-XXXXXXXXXXXX",
348
+ "ScreenSharingUrl": "wss://bitpw.m2.ue1.app.chime.aws:443/v2/screen/2f550432-579c-4058-bbb9-XXXXXXXXXXXX",
349
+ "ScreenViewingUrl": "wss://bitpw.m2.ue1.app.chime.aws:443/ws/connect?passcode=null&viewer_uuid=null&X-BitHub-Call-Id=2f550432-579c-4058-bbb9-XXXXXXXXXXXX",
350
+ "SignalingUrl": "wss://signal.m2.ue1.app.chime.aws/control/2f550432-579c-4058-bbb9-XXXXXXXXXXXX",
351
+ "TurnControlUrl": "https://ccp.cp.ue1.app.chime.aws/v2/turn_sessions"
352
+ },
353
+ "MediaRegion": "us-east-1",
354
+ "ApplicationMetadata": {
355
+ "MeetingType": "PrivateRoom",
356
+ "Room": {
357
+ "id": 1,
358
+ "name": "PrivateRoom-1",
359
+ "created_at": "2020-10-16T11:15:56.223Z",
360
+ "updated_at": "2020-10-16T11:15:56.223Z",
361
+ "members": [
362
+ {
363
+ "id": 1,
364
+ "provider": "email",
365
+ "uid": "ichiro@example.com",
366
+ "allow_password_change": false,
367
+ "name": "ichiro",
368
+ "nickname": null,
369
+ "image": null,
370
+ "email": "ichiro@example.com",
371
+ "created_at": "2020-10-16T11:14:48.731Z",
372
+ "updated_at": "2020-10-16T11:16:56.927Z"
373
+ },
374
+ {
375
+ "id": 2,
376
+ "provider": "email",
377
+ "uid": "stephen@example.com",
378
+ "allow_password_change": false,
379
+ "name": "stephen",
380
+ "nickname": null,
381
+ "image": null,
382
+ "email": "stephen@example.com",
383
+ "created_at": "2020-10-16T11:15:33.226Z",
384
+ "updated_at": "2020-10-16T11:15:33.314Z"
385
+ }
386
+ ]
387
+ }
388
+ }
389
+ },
390
+ "Attendee": {
391
+ "ExternalUserId": "ChimeSdkRailsApp-development-User-1",
392
+ "AttendeeId": "b581c46d-661f-92bb-d80e-XXXXXXXXXXXX",
393
+ "JoinToken": "YjU4MWM0NmQtNjYxZi05MmJiLWQ4MGUtZjRiMTU3ZDk1ZmU5OjgyZmM2NTMxLTIwMjctNGMxMS04OTE0LTQwZjXXXXXXXXXXXX",
394
+ "ApplicationMetadata": {
395
+ "AttendeeType": "User",
396
+ "User": {
397
+ "id": 1,
398
+ "provider": "email",
399
+ "uid": "ichiro@example.com",
400
+ "allow_password_change": false,
401
+ "name": "ichiro",
402
+ "nickname": null,
403
+ "image": null,
404
+ "email": "ichiro@example.com",
405
+ "created_at": "2020-10-16T11:14:48.731Z",
406
+ "updated_at": "2020-10-16T11:16:56.927Z"
407
+ }
408
+ }
409
+ }
410
+ }
411
+
412
+ # Get attendee data from created meeting ID
413
+
414
+ $ MEETING_ID=$(curl localhost:3000/api/v1/rooms/1/meetings -X POST -H "content-type:application/json" -H "${_ACCESS_TOKEN}" -H "${_CLIENT}" -H "${_UID}" | jq -r .Meeting.MeetingId)
415
+
416
+ $ curl localhost:3000/api/v1/rooms/1/meetings/${MEETING_ID}/attendees -H "content-type:application/json" -H "${_ACCESS_TOKEN}" -H "${_CLIENT}" -H "${_UID}" | jq .
417
+
418
+ {
419
+ "attendees": [
420
+ {
421
+ "Attendee": {
422
+ "ExternalUserId": "ChimeSdkRailsApp-development-User-1",
423
+ "AttendeeId": "b581c46d-661f-92bb-d80e-XXXXXXXXXXXX",
424
+ "JoinToken": "YjU4MWM0NmQtNjYxZi05MmJiLWQ4MGUtZjRiMTU3ZDk1ZmU5OjgyZmM2NTMxLTIwMjctNGMxMS04OTE0LTQwZjXXXXXXXXXXXX",
425
+ "ApplicationMetadata": {
426
+ "AttendeeType": "User",
427
+ "User": {
428
+ "id": 1,
429
+ "provider": "email",
430
+ "uid": "ichiro@example.com",
431
+ "allow_password_change": false,
432
+ "name": "ichiro",
433
+ "nickname": null,
434
+ "image": null,
435
+ "email": "ichiro@example.com",
436
+ "created_at": "2020-10-16T11:14:48.731Z",
437
+ "updated_at": "2020-10-16T11:16:56.927Z"
438
+ }
439
+ }
440
+ }
441
+ }
442
+ ]
443
+ }
444
+
445
+ $ ATTENDEE_ID=$(curl localhost:3000/api/v1/rooms/1/meetings/${MEETING_ID}/attendees -X GET -H "content-type:application/json" -H "${_ACCESS_TOKEN}" -H "${_CLIENT}" -H "${_UID}" | jq -r .attendees[0].Attendee.AttendeeId)
446
+
447
+ $ curl localhost:3000/api/v1/rooms/1/meetings/${MEETING_ID}/attendees/${ATTENDEE_ID} -H "content-type:application/json" -H "${_ACCESS_TOKEN}" -H "${_CLIENT}" -H "${_UID}" | jq .
448
+
449
+ {
450
+ "Attendee": {
451
+ "ExternalUserId": "ChimeSdkRailsApp-development-User-1",
452
+ "AttendeeId": "b581c46d-661f-92bb-d80e-XXXXXXXXXXXX",
453
+ "JoinToken": "YjU4MWM0NmQtNjYxZi05MmJiLWQ4MGUtZjRiMTU3ZDk1ZmU5OjgyZmM2NTMxLTIwMjctNGMxMS04OTE0LTQwZjXXXXXXXXXXXX",
454
+ "ApplicationMetadata": {
455
+ "AttendeeType": "User",
456
+ "User": {
457
+ "id": 1,
458
+ "provider": "email",
459
+ "uid": "ichiro@example.com",
460
+ "allow_password_change": false,
461
+ "name": "ichiro",
462
+ "nickname": null,
463
+ "image": null,
464
+ "email": "ichiro@example.com",
465
+ "created_at": "2020-10-16T11:14:48.731Z",
466
+ "updated_at": "2020-10-16T11:16:56.927Z"
467
+ }
468
+ }
469
+ }
470
+ }
471
+
472
+ # Sign in as stephen
473
+
474
+ $ curl localhost:3000/api/v1/auth/sign_in -X POST -H "content-type:application/json" -D auth_headers.txt -d '{"email":"stephen@example.com", "password":"password"}'
475
+
476
+ {"data":{"id":2,"email":"stephen@example.com","provider":"email","uid":"stephen@example.com","allow_password_change":false,"name":"stephen","nickname":null,"image":null}}
477
+
478
+ $ _ACCESS_TOKEN=$(cat auth_headers.txt | grep access-token | rev | cut -c 2- | rev)
479
+ $ _CLIENT=$(cat auth_headers.txt | grep client | rev | cut -c 2- | rev)
480
+ $ _UID=$(cat auth_headers.txt | grep uid | rev | cut -c 2- | rev)
481
+
482
+ # Confirm attending same meeting in the private room as different attendee
483
+
484
+ $ curl localhost:3000/api/v1/rooms/1/meetings -X POST -H "content-type:application/json" -H "${_ACCESS_TOKEN}" -H "${_CLIENT}" -H "${_UID}" | jq .
485
+
486
+ {
487
+ "Meeting": {
488
+ "MeetingId": "2f550432-579c-4058-bbb9-XXXXXXXXXXXX",
489
+ "ExternalMeetingId": "ChimeSdkRailsApp-development-PrivateRoom-1",
490
+ "MediaPlacement": {
491
+ "AudioHostUrl": "d3175d855e633b72aedbXXXXXXXXXXXX.k.m2.ue1.app.chime.aws:3478",
492
+ "AudioFallbackUrl": "wss://haxrp.m2.ue1.app.chime.aws:443/calls/2f550432-579c-4058-bbb9-XXXXXXXXXXXX",
493
+ "ScreenDataUrl": "wss://bitpw.m2.ue1.app.chime.aws:443/v2/screen/2f550432-579c-4058-bbb9-XXXXXXXXXXXX",
494
+ "ScreenSharingUrl": "wss://bitpw.m2.ue1.app.chime.aws:443/v2/screen/2f550432-579c-4058-bbb9-XXXXXXXXXXXX",
495
+ "ScreenViewingUrl": "wss://bitpw.m2.ue1.app.chime.aws:443/ws/connect?passcode=null&viewer_uuid=null&X-BitHub-Call-Id=2f550432-579c-4058-XXXXXXXXXXXX",
496
+ "SignalingUrl": "wss://signal.m2.ue1.app.chime.aws/control/2f550432-579c-4058-bbb9-XXXXXXXXXXXX",
497
+ "TurnControlUrl": "https://ccp.cp.ue1.app.chime.aws/v2/turn_sessions"
498
+ },
499
+ "MediaRegion": "us-east-1",
500
+ "ApplicationMetadata": {
501
+ "MeetingType": "PrivateRoom",
502
+ "Room": {
503
+ "id": 1,
504
+ "name": "PrivateRoom-1",
505
+ "created_at": "2020-10-16T11:15:56.223Z",
506
+ "updated_at": "2020-10-16T11:15:56.223Z",
507
+ "members": [
508
+ {
509
+ "id": 1,
510
+ "provider": "email",
511
+ "uid": "ichiro@example.com",
512
+ "allow_password_change": false,
513
+ "name": "ichiro",
514
+ "nickname": null,
515
+ "image": null,
516
+ "email": "ichiro@example.com",
517
+ "created_at": "2020-10-16T11:14:48.731Z",
518
+ "updated_at": "2020-10-16T11:16:56.927Z"
519
+ },
520
+ {
521
+ "id": 2,
522
+ "provider": "email",
523
+ "uid": "stephen@example.com",
524
+ "allow_password_change": false,
525
+ "name": "stephen",
526
+ "nickname": null,
527
+ "image": null,
528
+ "email": "stephen@example.com",
529
+ "created_at": "2020-10-16T11:15:33.226Z",
530
+ "updated_at": "2020-10-16T11:21:46.011Z"
531
+ }
532
+ ]
533
+ }
534
+ }
535
+ },
536
+ "Attendee": {
537
+ "ExternalUserId": "ChimeSdkRailsApp-development-User-2",
538
+ "AttendeeId": "986886fc-dcbc-1d44-4708-XXXXXXXXXXXX",
539
+ "JoinToken": "OTg2ODg2ZmMtZGNiYy0xZDQ0LTQ3MDgtOTE3YWIyMzExN2RlOjNjNjAzM2E5LWFlNGUtNGVmZi1iNjZjLWMwY2XXXXXXXXXXXX",
540
+ "ApplicationMetadata": {
541
+ "AttendeeType": "User",
542
+ "User": {
543
+ "id": 2,
544
+ "provider": "email",
545
+ "uid": "stephen@example.com",
546
+ "allow_password_change": false,
547
+ "name": "stephen",
548
+ "nickname": null,
549
+ "image": null,
550
+ "email": "stephen@example.com",
551
+ "created_at": "2020-10-16T11:15:33.226Z",
552
+ "updated_at": "2020-10-16T11:21:46.011Z"
553
+ }
554
+ }
555
+ }
556
+ }
557
+
558
+ $ MEETING_ID_2=$(curl localhost:3000/api/v1/rooms/1/meetings -X POST -H "content-type:application/json" -H "${_ACCESS_TOKEN}" -H "${_CLIENT}" -H "${_UID}" | jq -r .Meeting.MeetingId)
559
+
560
+ $ echo ${MEETING_ID}
561
+
562
+ 2f550432-579c-4058-bbb9-XXXXXXXXXXXX
563
+
564
+ $ echo ${MEETING_ID_2}
565
+
566
+ 2f550432-579c-4058-bbb9-XXXXXXXXXXXX
567
+ ```
568
+
569
+ Now you can start online meeting using [Amazon Chime SDK](https://aws.amazon.com/chime/chime-sdk) client-side implementation with this responded *Meeting* and *Attendee* data. You can see [customized React Meeting Demo](https://github.com/simukappu/amazon-chime-sdk/tree/main/apps/meeting) as a sample single page application using [React](https://reactjs.org/) and [Amazon Chime SDK for JavaScript](https://github.com/aws/amazon-chime-sdk-js). Enjoy your application development!