L'API Google Calendar v3 renvoie toujours BadRequest lors de la création d'événements

Aug 18 2020

J'ai créé un calendrier partagé et je souhaite ajouter des événements au calendrier.

J'ai créé un projet et mis en place un compte de service [email protected].

Ensuite, j'ai partagé le calendrier avec le compte de service en tant que propriétaire .

Puis j'ai remarqué

Le compte de service doit ajouter manuellement un calendrier partagé

comme décrit ici https://stackoverflow.com/a/62232361/298430 et https://issuetracker.google.com/issues/148804709

J'ai donc écrit un code:

 @Test
  fun addCalendarToServiceAccount() {

    val calList1: CalendarList = calendar.calendarList().list().execute()
    logger.info("calList1 = {}", calList1)

    val inserted = calendar.calendarList().insert(CalendarListEntry().setId(calendarId)).execute()
    logger.info("inserted = {}", inserted)

    val calList2: CalendarList = calendar.calendarList().list().execute()
    logger.info("calList2 = {}", calList2)
  }

Cela fonctionne parfaitement. Au premier appel, je peux voir qu'il calList1est vide et calList2contient quelque chose.

Ensuite, j'insère manuellement un événement dans le calendrier (avec l'interface utilisateur WEB de Google Agenda), je veux vérifier si je peux récupérer l'événement:

@Test
  fun listEvents() {
    val events: Events = calendar.events().list(calendarId).execute()
    logger.info("events = {}", events)
    events.items.forEachIndexed { index, e ->
      logger.info("Event [index = {}] , event = {}", index, e)
    }
  }

Cela fonctionne aussi.

{
   "accessRole":"owner",
   "defaultReminders":[

   ],
   "etag":"\"xxx\"",
   "items":[
      {
         "created":"2020-08-17T17:51:21.000Z",
         "creator":{
            "email":"[email protected]"
         },
         "end":{
            "date":"2020-08-20"
         },
         "etag":"\"xxx\"",
         "htmlLink":"https://www.google.com/calendar/event?eid=xxx",
         "iCalUID":"[email protected]",
         "id":"xxx",
         "kind":"calendar#event",
         "organizer":{
            "displayName":"xxx",
            "email":"[email protected]",
            "self":true
         },
         "reminders":{
            "useDefault":false
         },
         "sequence":0,
         "start":{
            "date":"2020-08-19"
         },
         "status":"confirmed",
         "summary":"xxx  test1",
         "transparency":"transparent",
         "updated":"2020-08-18T01:07:54.441Z"
      }
   ],
   "kind":"calendar#events",
   "nextSyncToken":"xxx",
   "summary":"xxx",
   "timeZone":"Asia/Taipei",
   "updated":"2020-08-18T01:07:54.688Z"
}

Ensuite, je veux insérer quelque chose par programme, comme le montre l'exemple d'API:

@Test
  fun testInsertEvent() {
    val now = LocalDateTime.now().withSecond(0).withNano(0)
    val zoneId = ZoneId.of("Asia/Taipei")
    val fromDate = Date.from(now.atZone(zoneId).toInstant())
    val endDate = Date.from(now.plusMinutes(60).atZone(zoneId).toInstant())

    val event = Event()
      .setSummary("Google I/O 2015")
      .setLocation("800 Howard St., San Francisco, CA 94103")
      .setDescription("A chance to hear more about Google's developer products.")
      .setStart(EventDateTime().setDate(DateTime(fromDate, TimeZone.getTimeZone(zoneId))))
      .setEnd(EventDateTime().setDate(DateTime(endDate, TimeZone.getTimeZone(zoneId))))

    logger.info("before insert event : {}", event)

    val eventResult: Event = calendar.events().insert(calendarId, event).execute()
    logger.info("eventResult = {}", eventResult)
  }

Je peux voir le client vraiment POST au point de terminaison google'e:

Le corps est:

{
   "description":"A chance to hear more about Google's developer products.",
   "end":{
      "date":"2020-08-18T11:32:00.000+08:00"
   },
   "location":"800 Howard St., San Francisco, CA 94103",
   "start":{
      "date":"2020-08-18T10:32:00.000+08:00"
   },
   "summary":"Google I/O 2015"
}

Mais Google vient de répondre à 400 BadRequest, sans autre description:

2020-08-18 10:32:15.974 [main] INFO  c.g.a.c.h.HttpResponse - -------------- RESPONSE --------------
HTTP/1.1 400 Bad Request
Transfer-Encoding: chunked
Alt-Svc: h3-29=":443"; ma=2592000,h3-27=":443"; ma=2592000,h3-T050=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"
Server: ESF
X-Content-Type-Options: nosniff
Pragma: no-cache
Date: Tue, 18 Aug 2020 02:32:15 GMT
X-Frame-Options: SAMEORIGIN
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Encoding: gzip
Vary: Referer
Vary: X-Origin
Vary: Origin
Expires: Mon, 01 Jan 1990 00:00:00 GMT
X-XSS-Protection: 0
Content-Type: application/json; charset=UTF-8

2020-08-18 10:32:15.980 [main] INFO  c.g.a.c.u.LoggingByteArrayOutputStream - Total: 171 bytes
2020-08-18 10:32:15.980 [main] INFO  c.g.a.c.u.LoggingByteArrayOutputStream - {
 "error": {
  "errors": [
   {
    "domain": "global",
    "reason": "badRequest",
    "message": "Bad Request"
   }
  ],
  "code": 400,
  "message": "Bad Request"
 }
}

J'utilise la même instance de calendrier , je peux réussir addCalendarToServiceAccount()(en tant que owner) et listEvents(). Mais qu'est-ce qui ne va pas lors de l'insertion d'un événement? Est-ce que j'ai manqué quelque chose?

Les autres champs sont initialisés comme suit:

  @Value("\${google.calendar.id}") private lateinit var calendarId: String @Value("\${google.calendar.apiKey}")
  private lateinit var apiKey : String

  private val httpTransport: HttpTransport by lazy {
    GoogleNetHttpTransport.newTrustedTransport()
  }

  private val jacksonFactory: JsonFactory by lazy {
    JacksonFactory.getDefaultInstance()
  }

  private val saCredentials: GoogleCredentials by lazy {
    javaClass.getResourceAsStream("/chancer-d1de03c4c25a.json").use { iStream ->
      ServiceAccountCredentials.fromStream(iStream)
        .createScoped(listOf(
          "https://www.googleapis.com/auth/cloud-platform",
          *CalendarScopes.all().toTypedArray()
        ))
    }.apply {
      refreshIfExpired()
    }
  }


  private val requestInitializer: HttpRequestInitializer by lazy {
    HttpCredentialsAdapter(saCredentials)
  }

  private val calendar: Calendar by lazy {
    Calendar.Builder(httpTransport, jacksonFactory, requestInitializer)
      .build()
  }

Environnements:

    <java.version>1.8</java.version>
    <kotlin.version>1.4.0</kotlin.version>


    <dependency>
      <groupId>com.google.api-client</groupId>
      <artifactId>google-api-client</artifactId>
      <version>1.30.10</version>
    </dependency>
    <dependency>
      <groupId>com.google.apis</groupId>
      <artifactId>google-api-services-calendar</artifactId>
      <version>v3-rev20200610-1.30.10</version>
    </dependency>
    <dependency>
      <groupId>com.google.auth</groupId>
      <artifactId>google-auth-library-oauth2-http</artifactId>
      <version>0.21.1</version>
    </dependency>

Réponses

2 RafaGuillermo Aug 18 2020 at 17:14

Répondre:

Vous devez utiliser start.dateTimeet end.dateTimeplutôt que start.dateetend.date

Réparer:

Selon la documentation :

end.date: La date, au format "aaaa-mm-jj", s'il s'agit d'un événement d'une journée entière.

end.dateTime: L'heure, sous forme de valeur combinée date-heure (formatée selon RFC3339). Un décalage de fuseau horaire est requis sauf si un fuseau horaire est explicitement spécifié dans timeZone .

start.date: La date, au format "aaaa-mm-jj", s'il s'agit d'un événement d'une journée entière.

start.dateTime: L'heure, sous forme de valeur combinée date-heure (formatée selon RFC3339). Un décalage de fuseau horaire est requis sauf si un fuseau horaire est explicitement spécifié dans timeZone .

Par conséquent, vous devez modifier votre méthode de réglage de la date et de l'heure à partir de:

EventDateTime().setDate(DateTime(fromDate, TimeZone.getTimeZone(zoneId))))

à:

EventDateTime().setDateTime(DateTime(fromDate, TimeZone.getTimeZone(zoneId))))

Ce qui changera le corps de la requête en:

{
  "description": "A chance to hear more about Google's developer products.",
  "end": {
      "dateTime": "2020-08-18T11:32:00.000+08:00" // modified
  },
  "location": "800 Howard St., San Francisco, CA 94103",
  "start": {
    "dateTime": "2020-08-18T10:32:00.000+08:00" // modified
  },
  "summary": "Google I/O 2015"
}

Vous pouvez voir la documentation de cette méthode ici .

J'espère que ça t'aide!

Références:

  • Événements: insérer | API de calendrier | Développeurs Google
  • RFC 3339 - Date et heure sur Internet: horodatages
  • EventDateTime (API de calendrier v3-rev20200610-1.30.10)