Search code examples
reactjsgoogle-apigoogle-calendar-api

Google API Calendar with Nodejs


what I want it to do

create calendar events when a client books. The calendar is a single employee owned calendar (example: [email protected])

I've successfully linked the api with my NextJS app with the server to server Service accounts method. When I create a calendar event, I can retrieve the data back in the terminal. When I go to log on to my account the UI is still blank

I've made sure

  • dates created relative to this year, easy to around today's date
  • I'm sending it to the 'primary' calendar

Am I wrong in thinking that the account that created the Google Cloud Console Project isn't automatically linked to these api calls?

From the account owner's calendar UI

I tried adding a new calendar with the + button with example [email protected] and got the error

You do not have access to [email protected]'s calendar.

request access

How am I supposed to access this .gserviceaccount.com email?

What I tried

after I created a few events from the api, I can return that data

/pages/api/google/create.ts

calendar.events.list({
    auth: jwtClient,
    calendarId: GOOGLE_CAL_ID
  }, function (err, response) {

    if(response) {
      console.log('----- here is responses ---- ');
      
      return console.log(response.data.items)
    };
    if(err) return console.log(err);
    
  });

terminal response

[
  {
    kind: 'calendar#event',
    etag: '"3366666430186000"',
    id: '5rbkghab02095kgoj0oc92u3ko',
    status: 'confirmed',
    htmlLink: 'https://www.google.com/calendar/event?eid=NXJia2doYWIwMjA5NWtnb2owb2M5MnUza28gY3V0ZWZydWl0LWNhbGVuZGVyQGN1dGVmcnVpdC1wcm9qZWN0LmlhbS5nc2VydmljZWFjY291bnQuY29t',
    created: '2023-05-06T00:33:35.000Z',
    updated: '2023-05-06T00:33:35.093Z',
    summary: 'Event 1',
    description: 'Sample description',
    creator: {
      email: '[email protected]',
      self: true
    },
    organizer: {
      email: '[email protected]',
      self: true
    },
    start: { dateTime: '2023-05-01T05:00:00Z', timeZone: 'America/Chicago' },
    end: { dateTime: '2023-05-01T06:00:00Z', timeZone: 'America/Chicago' },
    iCalUID: '[email protected]',
    sequence: 0,
    reminders: { useDefault: true },
    eventType: 'default'
  },
  ...,
  ...,
]

full file

import type { NextApiRequest, NextApiResponse } from 'next'

import { google } from 'googleapis';
import { JWT } from 'google-auth-library';
import creds from "../../../private/cutefruit-project.json";

const scopes = ['https://www.googleapis.com/auth/calendar'];
const GOOGLE_PRIVATE_KEY = creds.private_key|| 'NO_KEY_SET'
const GOOGLE_CLIENT_EMAIL = creds.client_email || 'NO_EMAIL_SET'
const GOOGLE_CAL_ID = 'primary'

let jwtClient = new JWT({
  email: GOOGLE_CLIENT_EMAIL,
  key: GOOGLE_PRIVATE_KEY,
  scopes,
})

//authenticate request
jwtClient.authorize(function (err, tokens) {
  console.log('JWT AUTHORIZATION');
  
  if (err) {
    console.log(err);
    return;
  } else {
    console.log("Successfully connected!")
  }
})

type Data = {
  name: string,
  data: any,
}

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse<Data>
) {

  const event = req.body

  let calendar = google.calendar('v3')

  calendar.events.insert({
    auth: jwtClient,
    calendarId: 'primary',
    requestBody: {
      'summary': 'Event 3',
      'description': 'Sample description',
      'start': {
        'dateTime': '2023-05-03T00:00:00',
        'timeZone': 'America/Chicago',
      },
      'end': {
        'dateTime': '2023-05-03T01:00:00',
        'timeZone': 'America/Chicago',
      },
    },
  }, function(err, res) {
    if (err) {
      console.log('Error: ' + err);
      return;
    }
    console.log(res?.status);
  })


  res.status(200).json({ name: 'cal event created', data: 'message response' })
}


Solution

  • answering my own question

    this article helped me understand the quarks of setting up the api via Service Account

    1. In your personal google account, create a new calendar
    2. SHARE the calendar to the Service Account email that was generated in the google cloud console. (example: [email protected])
    3. Copy that calendar's Calendar ID (example: bda948b786f16be2d763e0b2d3c699bc8230643f96bfbfb2at64b66e7fc92b11@group.calendar.google.com)
    4. Use that calendar ID in your api calls
    calendar.events.insert({
      auth: jwtClient,
      calendarId: GOOGLE_CAL_ID, // <-- here
      requestBody: event,
    })