[Ruby] [RSpec] Make the response of the request to the Google API stubbed with stub_request(:post) the same as the actual format

1 minute read

Long title

We added a process that updates the event on the calendar from the Rails application with the Google Calendar API and extracts a specific attribute from the response and handles it. The google-api-ruby-client will convert the JSON received in the response to an object of the Google::API::V3::Event class, so the response of the stub request will also be converted by ruby-client or a similar structure will be used. It had to be an object you had.

TL;DR

  • When requesting Google API using google-api-ruby-client, the response is returned in JSON format and then converted by google-api-ruby-client
  • If you add 'X-Goog-Upload-Status':'final' to the header of the return value from stub_request, the format will be the same as the response from the actual API.

Difference between stubized request and response when actually requesting to API

The code below makes a request using google-api-ruby-client and tries to get the event ID from the response

request

service = Google::Apis::CalendarV3::CalendarService.new
service.authorization = access_token

response = service.update_event('primary', event_id, body)
event_id = response.id

At this time, response is as follows.

#<Google::Apis::CalendarV3::Event:0x000055c94da58f18
 @attachments=[],
 @attendees=[#<Google::Apis::CalendarV3::EventAttendee:xxxxxxxxxxxxxxxxxxx @email="[email protected]", @organizer=true, @self=true>],
 @created=Mon, 01 Jan 2020 00:00:00 +0000,
 @creator=#<Google::Apis::CalendarV3::Event::Creator:xxxxxxxxxxxxxxxxxxx @email="[email protected]", @self=true>,
 @description="",
 @end=#<Google::Apis::CalendarV3::EventDateTime:xxxxxxxxxxxxxxxxxxx>,
 @etag="xxxxxxxxxxxxxxxxxxx",
 @id="abcdefghijklmnopqrstu",
 @organizer=#<Google::Apis::CalendarV3::Event::Organizer:xxxxxxxxxxxxxxxxxxx @email="[email protected]">,
 @start=#<Google::Apis::CalendarV3::EventDateTime:xxxxxxxxxxxxxxxxxxx>,
 @updated=Mon, 01 Jan 2020 00:00:00 +0000>

Therefore, the value can be fetched from the response object with the id of the getter method.

On the other hand, in most cases the API response will be defined in RSpec as:

let(:response) do
  {
    id:'abcdefghijklmnopqrstu',
    start: {date_time: Time.zone.today },
    end: {date_time: Time.zone.today },
    html_link:'https://www.google.com/calendar/event?eid=xxxxxxxxxxxxxxxxxxxxxxxxxxxx',
    i_cal_uid:'[email protected]',
    summary:'event name',
    updated: Time.zone.today,

    ...

  }.to_json
end

In this case, it is necessary to do something like JSON.parse(response)['id'] to get the event ID, and response.id becomes NoMethodError.

counter-measure

In order to return this JSON format response as an Event class object, it is necessary to add 'X-Goog-Upload-Status':'final' to the response header as shown below.

stub_request(
  :put, url
).to_return(
  status: 201,
  body: response,
  headers: {
    content_type:'application/json',
    'X-Goog-Upload-Status':'final'
  }
)

Even in the test spec of google-api-ruby-client the same header information is added to the response.

It happened because my co-worker happened to find an article or GitHub issue immediately, but if it wasn’t, I think I was addicted for 3 days.

Original material