Ta strona zawiera omówienie konwencji interfejsu API typu REST oraz indeks typowych zadań interfejsu Google Health API i przykłady każdego z nich.
Konwencje interfejsu API typu REST
Interfejs Google Health API jest zgodny ze standardami Google API Improvement Proposals (AIP), w szczególności z AIP-127 (HTTP and gRPC Transcoding) oraz AIP-131– AIP-135 (Standard Methods). Standardy te określają, jak dane są mapowane z komunikatu proto na żądanie HTTP.
Parametry zapytania
Parametry zapytania są używane, gdy dane są częścią adresu URL. Dotyczy to głównie żądań GET (pobieranie zasobu) lub LIST (filtrowanie/stronicowanie), ale także operacji DELETE.
- Umiejscowienie: dołączane do adresu URL po znaku
?. - Składnia: pary klucz-wartość rozdzielone znakiem
&. - Mapowanie: każde pole w komunikacie żądania, które nie jest częścią szablonu ścieżki URL , jest mapowane na parametr zapytania.
- Najlepsze w przypadku: prostych typów (ciągi znaków, liczby całkowite, wyliczenia) i pól powtarzających się.
Przykładowa składnia:
GET https://health.googleapis.com/v4/users/me/dataTypes/data-type/dataPoints?page_size=10&filter=data_type.interval.start_time >= "2025-10-01T00:00:00Z"
Treść żądania
Treść żądania jest używana, gdy dane modyfikują stan zasobu lub są zbyt duże, aby można je było umieścić w adresie URL. Treść jest zwykle reprezentacją JSON samego zasobu. Zwykle używana w przypadku operacji POST, PATCH i PUT.
- Umiejscowienie: w ładunku HTTP (niewidoczne w adresie URL).
- Składnia: sformatowana jako obiekt JSON.
- Mapowanie: zdefiniowane w adnotacji
google.api.http.body: "*"oznacza, że cała wiadomość jest treścią.body: "resource_name"oznacza, że tylko określone pole w proto jest treścią.
- Najlepsze w przypadku: złożonych obiektów, zagnieżdżonych wiadomości i danych wrażliwych.
Przykładowa składnia:
POST https://health.googleapis.com/v4/users/me/dataTypes/data-type/dataPoints:rollUp
Content-Type: application/json
{
"range": {
"startTime": "2025-11-05T00:00:00Z",
"endTime": "2025-11-13T00:00:00Z"
},
"windowSize": "3600s"
}Przypadek hybrydowy
W metodzie Update zgodnej z AIP-134 lub w operacji PATCH używane są obie te metody.
Adres URL zawiera nazwę zasobu, treść zawiera zaktualizowane dane zasobu, a parametr zapytania (zwykle update_mask) określa, które pola mają zostać zmienione.
PATCH https://health.googleapis.com/v4/projects/project-id/subscribers/subscriber-id
Content-Type: application/json
{
"endpointUri": "https://myapp.com/new-webhooks/health"
}
Kluczowe różnice w skrócie
| Funkcja | Parametry zapytania | Treść żądania |
|---|---|---|
| Wskazówki AIP | Używane do wyszukiwania, filtrowania i operacji odczytu. | Używane do operacji zapisu. |
| Widoczność | Widoczne w historii przeglądarki i logach serwera. | Ukryte w adresie URL. |
| Złożoność | Ograniczone do płaskich lub powtarzających się struktur. | Obsługuje głęboko zagnieżdżone obiekty JSON. |
| Kodowanie | Musi być zakodowane na potrzeby adresu URL (np. spacje stają się %20). |
Standardowe kodowanie JSON. |
Daty
Wszystkie daty w interfejsie Google Health API są wyświetlane w formacie YYYY-MM-DD. Interfejs Nutrition API obsługuje standard ISO-8601 w przypadku wartości dat z tymi warunkami:
- 4-cyfrowy rok
YYYY - Wartości roku w zakresie 0000–9999
- Brak egzekwowania ograniczeń daty rozpoczęcia wynikających ze standardu ISO-8601 lub innej epoki
Nagłówki
Wykonanie punktów końcowych interfejsu Google Health API wymaga użycia odpowiednich nagłówków i tokena dostępu. W przypadku żądań GET i POST zalecamy użycie tego nagłówka:
Authorization: Bearer access-token Accept: application/json
Indeks zadań interfejsu API
Ta sekcja zawiera indeks typowych zadań interfejsu Google Health API i przykłady każdego z nich.
Pobieranie identyfikatora użytkownika Fitbit lub Google
Gdy użytkownik wyrazi zgodę za pomocą Google OAuth 2.0, odpowiedź tokena nie będzie zawierać identyfikatora użytkownika Fitbit ani Google. Aby uzyskać identyfikator użytkownika, wywołaj
getIdentity punkt końcowy. getIdentity
zwraca zarówno starszy identyfikator użytkownika Fitbit, jak i identyfikator użytkownika Google.
Zalecamy, aby po wyrażeniu zgody przez nowego użytkownika za pomocą OAuth wywołać punkt końcowy getIdentity i zapisać oba identyfikatory użytkownika. Zapewnia to zgodność wsteczną i przyszłą w integracji.
Na przykład:
Żądanie
GET https://health.googleapis.com/v4/users/me/identity Authorization: Bearer access-token Accept: application/json
Odpowiedź
{
"name": "users/me/identity",
"legacyUserId": "A1B2C3",
"healthUserId": "111111256096816351"
}Pobieranie danych śródrocznych lub szczegółowych zebranych w ciągu dnia
Aby uzyskać dane śródroczne lub szczegółowe zebrane w ciągu dnia w
obsługiwanych przedziałach czasu dla danego typu danych, użyj list
punktu końcowego dla określonego
typu danych.
Na przykład:
Żądanie
GET https://health.googleapis.com/v4/users/me/dataTypes/steps/dataPoints Authorization: Bearer access-token Accept: application/json
Odpowiedź
{
"dataPoints": [
{
"dataSource": {
"recordingMethod": "PASSIVELY_MEASURED",
"device": {
"manufacturer": "",
"displayName": "Charge 6"
},
"platform": "FITBIT"
},
"steps": {
"interval": {
"startTime": "2026-03-04T07:05:00Z",
"startUtcOffset": "0s",
"endTime": "2026-03-04T07:06:00Z",
"endUtcOffset": "0s",
"civilStartTime": {
"date": {
"year": 2026,
"month": 3,
"day": 4
},
"time": {
"hours": 7,
"minutes": 5
}
},
"civilEndTime": {
"date": {
"year": 2026,
"month": 3,
"day": 4
},
"time": {
"hours": 7,
"minutes": 6
}
}
},
"count": "40"
}
},
...
],
"nextPageToken": "Xm5h-6L0viZxIlRuWjx5bmvy98zj85uG34tuMn16mu2pntsnZI32iqhq"
}Filtrowanie danych według czasu rozpoczęcia przedziału czasu
Aby filtrować dane według czasu cywilnego lub przedziału czasu, użyj punktu końcowego list z parametrem filter.
Na przykład:
Żądanie
GET https://health.googleapis.com/v4/users/me/dataTypes/steps/dataPoints?filter=steps.interval.civil_start_time >= "2026-03-04T00:00:00" Authorization: Bearer access-token Accept: application/json
Odpowiedź
{
"dataPoints": [
{
"dataSource": {
"recordingMethod": "PASSIVELY_MEASURED",
"device": {
"manufacturer": "",
"displayName": "Charge 6"
},
"platform": "FITBIT"
},
"steps": {
"interval": {
"startTime": "2026-03-04T07:05:00Z",
"startUtcOffset": "0s",
"endTime": "2026-03-04T07:06:00Z",
"endUtcOffset": "0s",
"civilStartTime": {
"date": {
"year": 2026,
"month": 3,
"day": 4
},
"time": {
"hours": 7,
"minutes": 5
}
},
"civilEndTime": {
"date": {
"year": 2026,
"month": 3,
"day": 4
},
"time": {
"hours": 7,
"minutes": 6
}
}
},
"count": "40"
}
...
],
"nextPageToken": "Xm5h-6L0viZxIlRuQjp5bml1bZ4ve2dhNmZvMnt4Yn7qIGQhbHN3YQ"
}Filtrowanie danych według czasu fizycznego obserwacji próbki
Aby filtrować dane według czasu fizycznego obserwacji próbki, użyj punktu końcowego list z parametrem filter.
Na przykład:
Żądanie
GET https://health.googleapis.com/v4/users/me/dataTypes/body-fat/dataPoints?filter=body_fat.sample_time.physical_time >= "2026-03-01T00:00:00Z" Authorization: Bearer access-token Accept: application/json
Odpowiedź
{
"dataPoints": [
{
"name": "users/2515055256096816351/dataTypes/body-fat/dataPoints/1234567890",
"dataSource": {
"recordingMethod": "UNKNOWN",
"application": {
"packageName": "",
"webClientId": "",
"googleWebClientId": "google-web-client-id"
},
"platform": "GOOGLE_WEB_API"
},
"-->bodyFat<--": {
"sampleTime": {
"physicalTime": "2026-03-10T10:00:00Z",
"utcOffset": "0s",
"civilTime": {
"date": {
"year": 2026,
"month": 3,
"day": 10
},
"time": {
"hours": 10
}
}
},
"percentage": 20
}
}
"nextPageToken": ""
}Filtrowanie danych według źródeł danych, takich jak urządzenia do noszenia
Aby uzyskać dane dla określonej "rodziny źródeł danych", użyj reconcile
punktu końcowego. Aby to zrobić, określ parametr dataSourceFamily jako parametr zapytania.
W tabeli poniżej opisujemy obsługiwane opcje dataSourceFamily:
| Opcja | Opis |
|---|---|
users/me/dataSourceFamilies/all-sources |
Wartość domyślna. Zawiera dane ze wszystkich dostępnych źródeł danych. |
users/me/dataSourceFamilies/google-wearables |
Zawiera dane z urządzeń Google i Fitbit (takich jak trackery Fitbit i Pixel Watch). Wyklucza dane logowane ręcznie. |
users/me/dataSourceFamilies/google-sources |
Zawiera dane własne Google, takie jak dane z urządzeń śledzących i dane logowane ręcznie. |
Oto przykład filtrowania tylko snu zarejestrowanego przez tracker w dniu po 2026-03-03:
Żądanie
GET https://health.googleapis.com/v4/users/me/dataTypes/sleep/dataPoints:reconcile?dataSourceFamily=users/me/dataSourceFamilies/google-wearables&filter=sleep.interval.civil_end_time >= "2026-03-03" Authorization: Bearer access-token Accept: application/json
Odpowiedź
{
"dataPoints": [
{
"name": "users/2515055256096816351/dataTypes/sleep/dataPoints/2724123844716220216",
"dataSource": {
"recordingMethod": "DERIVED",
"device": {
"displayName": "Charge 6"
},
"platform": "FITBIT"
},
"sleep": {
"interval": {
"startTime": "2026-03-03T20:57:30Z",
"startUtcOffset": "0s",
"endTime": "2026-03-04T04:41:30Z",
"endUtcOffset": "0s"
},
"type": "STAGES",
"stages": [
{
"startTime": "2026-03-03T20:57:30Z",
"startUtcOffset": "0s",
"endTime": "2026-03-03T20:59:30Z",
"endUtcOffset": "0s",
"type": "AWAKE",
"createTime": "2026-03-04T04:43:40.937183Z",
"updateTime": "2026-03-04T04:43:40.937183Z"
},
…
{
"startTime": "2026-03-04T04:07:30Z",
"startUtcOffset": "0s",
"endTime": "2026-03-04T04:41:30Z",
"endUtcOffset": "0s",
"type": "AWAKE",
"createTime": "2026-03-04T04:43:40.937183Z",
"updateTime": "2026-03-04T04:43:40.937183Z"
}
],
"metadata": {
"stagesStatus": "SUCCEEDED",
"processed": true,
"main": true
},
"summary": {
"minutesInSleepPeriod": "464",
"minutesAfterWakeUp": "0",
"minutesToFallAsleep": "0",
"minutesAsleep": "407",
"minutesAwake": "57",
"stagesSummary": [
{
"type": "AWAKE",
"minutes": "56",
"count": "12"
},
{
"type": "LIGHT",
"minutes": "198",
"count": "19"
},
{
"type": "DEEP",
"minutes": "114",
"count": "10"
},
{
"type": "REM",
"minutes": "94",
"count": "4"
}
]
},
"createTime": "2026-03-04T04:43:40.337983Z",
"updateTime": "2026-03-04T04:43:40.937183Z"
}
}
],
"nextPageToken": ""
}Agregowanie punktów danych w przedziale czasu
Aby zwrócić agregację punktów danych na podstawie okna w sekundach w zakresie datetime na podstawie czasu fizycznego użytkowników (w UTC), użyj rollUp
punktu końcowego.
Podczas wywoływania punktu końcowego rollUp musisz podać treść żądania reprezentującą wymagany zakres dat w czasie cywilnym użytkownika. Na przykład:
Żądanie
POST https://health.googleapis.com/v4/users/me/dataTypes/steps/dataPoints:rollUp
Authorization: Bearer access-token
Accept: application/json
{
"range": {
"startTime": "2026-02-17T17:00:00Z",
"endTime": "2026-02-17T17:59:59Z"
},
"windowSize": "30s"
}Odpowiedź
{
"rollupDataPoints": [
{
"startTime": "2026-02-17T17:55:00Z",
"endTime": "2026-02-17T17:55:30Z",
"steps": {
"countSum": "41"
}
},
{
"startTime": "2026-02-17T17:54:00Z",
"endTime": "2026-02-17T17:54:30Z",
"steps": {
"countSum": "31"
}
},
...
]
}Agregowanie danych z jednego lub kilku dni
Punkt końcowy dailyRollUp
należy
stosować, gdy chcesz agregować dane z
jednego lub kilku dni, czyli windowSize. W treści żądania podaj zakres czasu cywilnego zamknięty-otwarty dla wymaganego przedziału czasu. W zależności od typu danych otrzymasz sumę lub średnią z przedziału.
Na przykład:
Żądanie
POST https://health.googleapis.com/v4/users/me/dataTypes/steps/dataPoints:dailyRollUp
Authorization: Bearer access-token
Accept: application/json
{
"range": {
"start": {
"date": {
"year": 2026,
"month": 2,
"day": 26
},
"time": {
"hours": 0,
"minutes": 0,
"seconds": 0,
"nanos": 0
}
},
"end": {
"date": {
"year": 2026,
"month": 2,
"day": 26
},
"time": {
"hours": 23,
"minutes": 59,
"seconds": 59,
"nanos": 0
}
}
},
"windowSizeDays": 1
}Odpowiedź
{
"rollupDataPoints": [
{
"civilStartTime": {
"date": {
"year": 2026,
"month": 2,
"day": 26
},
"time": {}
},
"civilEndTime": {
"date": {
"year": 2026,
"month": 2,
"day": 26
},
"time": {
"hours": 23,
"minutes": 59,
"seconds": 59
}
},
"steps": {
"countSum": "3822"
}
}
]
}Wstawianie lub aktualizowanie danych dotyczących zdrowia użytkownika
Aby wstawić lub zaktualizować dane użytkownika w aplikacji Fitbit, użyj patch
punktu końcowego.
Oto przykład, w którym użytkownik zarejestrował poziom tkanki tłuszczowej na wadze o nazwie „HumanScale” firmy „Scales R Us”. Nowy odczyt tkanki tłuszczowej użytkownika wynosi 20% w dniu 2026-03-10.
Żądanie
PATCH https://health.googleapis.com/v4/users/me/dataTypes/body-fat/dataPoints/1234567890
Authorization: Bearer access-token
content-length: 329
{
"name": "bodyFatName",
"dataSource": {
"recordingMethod": "ACTIVELY_MEASURED",
"device": {
"formFactor": "SCALE",
"manufacturer": "Scales R Us",
"displayName": "HumanScale"
}
},
"bodyFat": {
"sampleTime": {
"physicalTime": "2026-03-10T10:00:00Z"
},
"percentage": 20
}
}Odpowiedź
{
"done": true,
"response": {
"@type": "type.googleapis.com/google.devicesandservices.health.v4main.DataPoint",
"name": "users/2515055256096816351/dataTypes/body-fat/dataPoints/1234567890",
"dataSource": {
"recordingMethod": "ACTIVELY_MEASURED",
"device": {
"formFactor": "SCALE",
"manufacturer": "Scales R Us",
"displayName": "HumanScale"
},
"application": {
"googleWebClientId": "618308034039.apps.googleusercontent.com"
},
"platform": "GOOGLE_WEB_API"
},
"bodyFat": {
"sampleTime": {
"physicalTime": "2026-03-10T10:00:00Z"
},
"percentage": 20
}
}
}Rejestrowanie produktu spożywczego
Aby zarejestrować produkt spożywczy, wyślij żądanie POST do punktu końcowego dataPoints nutrition-log. Treść żądania zawiera DataPoint z obiektem nutritionLog.
Więcej informacji znajdziesz w przewodniku po odżywianiu.
Na przykład:
Żądanie
POST https://health.googleapis.com/v4/users/me/dataTypes/nutrition-log/dataPoints
Authorization: Bearer access-token
Content-Type: application/json
{
"nutritionLog": {
"interval": {
"startTime": "2026-06-16T12:00:00Z",
"endTime": "2026-06-16T12:30:00Z"
},
"foodDisplayName": "Banana",
"mealType": "LUNCH",
"energy": {
"kcal": 105
},
"totalCarbohydrate": {
"grams": 27
},
"totalFat": {
"grams": 0.3
}
}
}Odpowiedź
{
"done": true,
"response": {
"@type": "type.googleapis.com/google.devicesandservices.health.v4.DataPoint",
"name": "users/2515055256096816351/dataTypes/nutrition-log/dataPoints/567890",
"dataSource": {
"recordingMethod": "ACTIVELY_MEASURED",
"platform": "GOOGLE_WEB_API"
},
"nutritionLog": {
"interval": {
"startTime": "2026-06-16T12:00:00Z",
"startUtcOffset": "0s",
"endTime": "2026-06-16T12:30:00Z",
"endUtcOffset": "0s"
},
"energy": {
"kcal": 105
},
"totalCarbohydrate": {
"grams": 27
},
"totalFat": {
"grams": 0.3
},
"mealType": "LUNCH",
"foodDisplayName": "Banana"
}
}
}Usuwanie danych dotyczących zdrowia użytkownika
Aby usunąć tablicę danych użytkownika w aplikacji Fitbit, użyj batchDelete
metody.
Oto przykład, w którym użytkownik wcześniej zarejestrował poziom tkanki tłuszczowej na wadze, ale chce usunąć ten rekord. Używanie user-id i data-point-id z pierwotnej operacji wstawiania:
Żądanie
POST https://health.googleapis.com/v4/users/me/dataTypes/body-fat/dataPoints:batchDelete
Authorization: Bearer access-token
Accept: application/json
content-length: 93
{
"names": [
"users/2515055256096816351/dataTypes/body-fat/dataPoints/1234567890"
]
}Odpowiedź
{
"done": true,
"response": {
"@type": "type.googleapis.com/google.devicesandservices.health.v4main.BatchDeleteDataPointsResponse"
}
}Znajdowanie informacji o urządzeniu
Aby pobrać listę urządzeń sparowanych z kontem użytkownika, użyj punktu końcowego list do. Obejmuje to informacje o modelu urządzenia (deviceVersion) i czas ostatniej synchronizacji z aplikacją mobilną Google Health (lastSyncTime).
Informacje o konfiguracji listy i synchronizacji są przydatne do rozwiązywania problemów z synchronizacją lub pobierania danych historycznych od czasu ostatniej synchronizacji.
Na przykład:
Żądanie
GET https://health.googleapis.com/v4/users/me/pairedDevices Authorization: Bearer access-token Accept: application/json
Odpowiedź
{
"pairedDevices": [
{
"name": "users/me/pairedDevices/123456",
"deviceType": "TRACKER",
"batteryStatus": "High",
"batteryLevel": 88,
"lastSyncTime": "2026-03-04T07:05:00Z",
"deviceVersion": "Charge 6",
"macAddress": "00:11:22:33:44:55",
"features": [
"STEPS",
"HEART_RATE"
]
}
]
}Wykonywanie zapytań o dane historyczne
Jedną z głównych korzyści interfejsu Google Health API jest możliwość śledzenia wyników użytkownika i monitorowania jego parametrów życiowych przez długi czas. Możesz wysyłać zapytania o dane użytkownika tak daleko, jak zostały zarejestrowane. Interfejs API nie nakłada żadnych ograniczeń na ilość danych historycznych, które może wykorzystywać Twoja aplikacja.
Wysyłanie zapytań o dane historyczne podlega jednak standardowym limitom liczby żądań. Aby zapewnić stabilność systemu i zapobiec nadmiernym ładunkom, interfejs Google Health API używa automatycznego stronicowania z rozmiarami stron specyficznymi dla punktu końcowego. Pamiętaj o tych granicach i zachowaniach:
- Automatyczne stronicowanie: jeśli wysyłasz zapytanie o długi zakres danych, interfejs
API zwróci tylko pierwszą stronę wyników do limitu rozmiaru strony dla tego
punktu końcowego wraz z tokenem
nextPageToken. Aby poprosić o kolejne strony, musisz użyćnextPageToken. - Zmienne rozmiary stron: limity zależą od punktu końcowego
i typu danych. W przypadku większości typów danych rozmiary stron są ograniczone do maksymalnie 10 tys.
W przypadku niektórych typów danych, takich jak
exerciseisleep, domyślny i maksymalny rozmiar strony jest ograniczony do 25. Jeśli na przykład klient poprosi o wszystkie dane o śnie z ostatnich 10 lat, interfejs API nadal zwróci tylko 25 sesji snu na pierwszej stronie. - Ograniczenia zakresu dat podsumowania: w przypadku punktów końcowych agregacji danych i podsumowania
(takich jak
rollUpidailyRollUp) zakresy dat zapytań są ograniczone w zależności od typu danych:- Maksymalny zakres 14 dni w przypadku
calories-in-heart-rate-zone,heart-rate,active-minutesitotal-calories. - Maksymalny zakres 90 dni w przypadku wszystkich innych typów danych agregacji.
- Maksymalny zakres 14 dni w przypadku
W zależności od ilości danych historycznych, których potrzebuje Twoja aplikacja, pobranie całego zbioru danych będzie wymagało sekwencyjnego stronicowania. Pamiętaj o tym podczas projektowania procesu synchronizacji danych aplikacji.
Aby zapewnić optymalną wydajność i uniknąć błędów interfejsu API, podczas wysyłania zapytań o dane historyczne postępuj zgodnie z tymi wskazówkami:
Synchronizacja danych etapami (wczytywanie na gorąco i wczytywanie „na zimno”)
- Początkowe wczytywanie „na gorąco”: podczas głównej sekwencji wczytywania pobieraj i renderuj tylko dane z ostatnich 7–14 dni. Dzięki temu użytkownicy od razu widzą dane bez czekania na długotrwałe zapytania.
- Wczytywanie „na zimno” w tle: po wyrenderowaniu głównego interfejsu użytkownika deleguj pobieranie starszych danych historycznych do asynchronicznej kolejki o niższym priorytecie lub procesu w tle.
Dzielenie zapytań na potrzeby agregacji
- Ponieważ punkty końcowe agregacji i agregacji dziennej wymuszają maksymalny limit zakresu dat (14 lub 90 dni w zależności od typu danych), musisz podzielić duże zapytania o agregację historyczną na mniejsze, sekwencyjne przedziały czasu w tych limitach.
- Bezpiecznie grupuj lub sekwencjonuj te podzapytania, aby zachować limity współbieżności i utrzymywać stałe wskaźniki postępu interfejsu użytkownika.
Wykorzystywanie wstępnie zagregowanych agregacji
Zmień strukturę paneli przeglądowych i wykresów trendów, aby używać wstępnie zagregowanych punktów końcowych podsumowania (takich jak DailyRollUpDataPoints). Znacznie zmniejszy to obciążenie obliczeniowe na backendzie i czas przesyłania danych do klienta.
Odporna obsługa błędów (inteligentne ponawianie)
- W przypadku napotkania limitów liczby żądań (
429 Too Many Requests) i przekroczenia limitu czasu bramy serwera (504 Gateway Timeout) wdróż ścisłe stosowanie wzrastającego czasu do ponowienia. Nigdy nie ponawiaj od razu dużych, nieudanych ładunków. Natychmiastowe ponawianie zwiększa przeciążenie backendu i pogarsza działanie systemu.