Next.js Discord

Discord Forum

How To Set Up Google API Push Notifications

Answered
West African Lion posted this in #help-forum
Open in Discord
West African LionOP
This is a continuation of the following thread - https://canary.discord.com/channels/752553802359505017/1239944959357091960

I'm trying to set up a push notification using the Google Calendar API, but running into issues despite reading over the docs several times. In the docs, it states you need to set up a channel for the "webhook," but I'm not entirely sure where I can do that and where I would tell the callback to go to the endpoint I create.

I've tried using Insomnia, but keep getting the following error:
{
    "error": {
        "errors": [
            {
                "domain": "global",
                "reason": "parseError",
                "message": "Parse Error"
            }
        ],
        "code": 400,
        "message": "Parse Error"
    }
}

This is using the API key I created for the project. If I don't add it, it states that I can't use this endpoint anonymously so it must be reading it somehow, I assume.

Any help you can provide would be greatly appreciated!

Edit: Here are the docs I was talking about - https://developers.google.com/calendar/api/guides/push#overview

106 Replies

West African LionOP
@American Crow - This is the new thread specifically about this issue.
In response to you message: https://canary.discord.com/channels/752553802359505017/1239944959357091960/1240211242296016896

I tried using Insomnia to make the request, but keep getting the error above. I'm certain that some gap in my knowledge is the root to my struggle, but without knowing what I don't know, I'm lost 😦 Any additional advice you can provide would be greatly appreciated!
@American Crow Provide some more info on your post request. Obviously hide the api keys / secrets but i need to see some more
West African LionOP
So this is what I was doing in Insomnia:
I also tried to use Google's npm package when making requests for the calendar, but I'm missing something and can't seem to authenticate with the server so I ended up using a regular fetch request.
@West African Lion So this is what I was doing in Insomnia:
American Crow
Sorry can you just show raw json which gets sent ? i am not familiar with insomnia
West African LionOP
Oh sorry! Here you go:
{
  "id": "01234567-89ab-cdef-0123456789ab",
  "type": "web_hook",
  "address": "https://mydomain.com/notifications"
}
American Crow
Does the <CALID> get resolved correctly in the URL (insomina screenshot) ?
if that is an insomnia thing i dont know maybe hardcode it for now
or is that you hiding it in the screenshot
West African LionOP
I edited that just for the screenshot
American Crow
okay
West African LionOP
If I could figure out the Service Account Auth, maybe it would be much easier since I could use the npm package they have googleapis
American Crow
Lets try to get the post request to work first you can still do a service account later if you want to
show me your headers in insomnia
(hide secrets)
West African LionOP
This is all I have in the headers
You saw the key in the API Key tab
American Crow
Where is the bearer token attached? Sorry i would know all this in postman
can you choose bearer here ? or somth similar
In Postman i'd do this:
which adds it to the heade rlike that:
I don't see that happening anywhere in your screenshots
West African LionOP
I don't have that
Where would I the token from?
I can switch to using Postman for now
Let me set it up, one sec
It's an option instead of API key
but I don't know where to get the token from
American Crow
Google calls it that.
... (as identified by the OAuth 2.0 client IDs from the auth tokens) who created the channel can stop the channel. So I'd guess they are talking about: https://console.cloud.google.com/apis/credentials . Sorry i have also never used the calendar API so i am assuming its just the regular oauth
West African LionOP
So I don't use OAuth 2.0 since this isn't a person that's trying to authenticate but a server
That's why I was using the api key
West African LionOP
My friend said this is what I need for creating channels
https://cloud.google.com/monitoring/support/notification-options#webhooks
West African LionOP
Hey @American Crow
I'm working with someone at Google to figure out things on their end, but I'm hoping to get ahead and prepare the API endpoint.

I got a working route handler
https://localhost:3000/api/calender and it returns "Hello World"
export async function GET() {
    console.log("Message received!")
    return Response.json({ data: "Hello, World!" })
}


What I'm unsure about is how to get this to revalidate the data. For now, I'll just test it manually by using Postman to hit the endpoint.

I tried following this guide, but all they are doing is returning a JSON. Nothing about how to tell the app to revalidate unless I'm missing something.

https://nextjs.org/docs/app/building-your-application/routing/route-handlers#revalidating-cached-data
Answer
@American Crow https://nextjs.org/docs/app/api-reference/functions/revalidatePath
West African LionOP
I see, thank you!

What is the difference between a server action and a route handler?
I'm really sorry to keep bugging you
Something in my understanding is missing and I don't know what it is that is causing me to just not get this pattern
@West African Lion I see, thank you! What is the difference between a server action and a route handler?
American Crow
Server actions and Route Handler are technically very similar under hood. If you use server actions the action itself actually creates a route handler (endpoint) under the hood. The default way is to go with server actions because you are saving one network trip. However there are some expections. One for instance, server actions can not be called from external (thats your case), so you have to go with a route handler.
West African LionOP
I see
American Crow
In your case it doesnt really matter what the route handler actually returns it just has to execute the revalidatePathfunction
West African LionOP
So I would need something like this?
import { revalidatePath } from 'next/cache'
import type { NextRequest } from 'next/server'
 
export async function GET(request: NextRequest) {
  const path = request.nextUrl.searchParams.get('path')
 
  if (path) {
    revalidatePath(path)
    return Response.json({ revalidated: true, now: Date.now() })
  }
 
  return Response.json({
    revalidated: false,
    now: Date.now(),
    message: 'Missing path to revalidate',
  })
}


so then I'd point gcloud at this?
https://mydomain.com/api/revalidate
American Crow
nobody will read your response from the handler (google doesnt care and you also don't really care)
West African LionOP
So how do I tell it to revalidate
Where is the snippet of code connecting this handler with the actual page I need revalidated
American Crow
as stated the revalidatePathfunction
West African LionOP
So it just knows where my website is and has the function calls to revalidate it automatically?
import { revalidatePath } from 'next/cache'
revalidatePath('/blog/post-1')


So I don't need something like this?
American Crow
if its your homepage you want to revalidate it's make it revlidatePath('/')
i don't know which page you want revalidated
West African LionOP
I want the map component on the page revalidated but it is all on a single page
so the root page would be it for this instance
American Crow
yea if its the index page (home page, landing page)
revalidatePath('/')
West African LionOP
so it'll look like this:
import { revalidatePath } from 'next/cache'
import type { NextRequest } from 'next/server'
 
export async function GET() {
  revalidatePath('/')
  return Response.json({ revalidated: true, now: Date.now() })
}
American Crow
yea
but post
i think google wanted a post
West African LionOP
and anything hitting this endpoint will cause a revalidation
I see
Do I need to worry about security in any way?
West African LionOP
Like, this just let's anyone revalidate right?
@West African Lion Do I need to worry about security in any way?
American Crow
yea there were tokens and shit in the Google docs to make sure that only certain external systems can call the endpoint
West African LionOP
Can I test this locally with the path and just localhost:3000/API/revalidate using Postman, right?
American Crow
yes
West African LionOP
Got it
I think this is making sense now
I'm sorry for the mess!
American Crow
all good i think you unlocked a new concept in your head called webhooks :galactic_brain:
West African LionOP
Unlocked is a strong word...
lol
American Crow
well concept is equally weak 😄
West African LionOP
I think I just started the progression of this achievement lol
Thanks again, truly!
American Crow
pretty sure you got the concept though, mastering is another thing. you welcome
@American Crow pretty sure you got the concept though, mastering is another thing. you welcome
West African LionOP
So, I created the endpoint as we discussed, but when I hit it manually using Postman or Chrome, nothing happened. Do you have any ideas? Did I miss something?
I'm getting a response:
{"revalidated":true,"now":1715880283823}
@West African Lion So, I created the endpoint as we discussed, but when I hit it manually using Postman or Chrome, nothing happened. Do you have any ideas? Did I miss something? I'm getting a response: `{"revalidated":true,"now":1715880283823}`
American Crow
Did you do your whole setup as in the video from the first post?
E.g. changing some date or time in the google calendar and instead of hitting the refresh button in the browser, hit the api endpoint ?
Fresh data should be shown once the api endpoint was hit
@West African Lion Yeah, and even with a refresh, nothing happens
American Crow
Wait a refresh of your homepage should always pull the latest data, that already worked in your last video. You sure you didn't break somth. on the way?
West African LionOP
No, that video was in localhost, so any refresh would cause a complete data refetch
American Crow
Okay now info rolls in
Did you make it a POST or GET endpoint?
West African LionOP
get
American Crow
GET endpoints are cached by default in Nextjs
try post
West African LionOP
import { revalidatePath } from 'next/cache'

export async function GET() {
    revalidatePath('/')
    console.log("Revalidated")
    return Response.json({ revalidated: true, now: Date.now() })
}
so this?
export async function POST() {
    revalidatePath('/')
    console.log("Revalidated")
    return Response.json({ revalidated: true, now: Date.now() })
}
American Crow
yea
you can also throw in a dynamic function to be double sure it will also opt out:

export async function POST() {
    headers() // opt out of caching
    revalidatePath('/')
    console.log("Revalidated")
    return Response.json({ revalidated: true, now: Date.now() })
}
West African LionOP
done building so let me test it
It hates me 😦
Not sure what I'm doing wrong
I g2g, but I'll be on later. Thank you again for all of the help ❤️ I'm totally lost with these things 😦
American Crow
Okay. There are other caching layers in Nextjs so another time we need check those as well.
As a first step i'd go to developer console in your browser, disable caching and refresh, see if that pulls in new data or not in production/build version
West African LionOP
I did some tests, and when I went back in before making any changes, the changes I made in the video showed up
I did the same thing as in the video, and after a minute, refreshed
Seems to be working I think
Will look at it more when I get back
@American Crow Okay. There are other caching layers in Nextjs so another time we need check those as well. As a first step i'd go to developer console in your browser, disable caching and refresh, see if that pulls in new data or not in production/build version
West African LionOP
I have updates!

I learned that the issue I was facing was due to a misconfigured account. I talked to Google, but they are unsure what is going on, so we are investigating it. In the meantime, I used a different Google account to create the service account credentials.

The website does update after making any change to the calendar, but what I'm trying to figure out is regarding what you said earlier:
Fresh data should be shown once the API endpoint was hit
I'm still required to refresh the page for it to display, and it takes about 30s (don't know if that's expected or not).