Na tej stronie znajdziesz omówienie konwencji interfejsu REST API oraz indeks typowych zadań interfejsu Google Health API i przykłady każdego z nich.
Konwencje API REST
Interfejs Google Health API jest zgodny ze standardami propozycji ulepszeń interfejsów API Google (AIP), a w szczególności z AIP-127 (transkodowanie HTTP i gRPC) oraz AIP-131–AIP-135 (metody standardowe). Te standardy określają, jak dane są mapowane z wiadomości protokołu 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 jest też używane w przypadku operacji DELETE.
- Miejsce docelowe: dołączone do adresu URL po znaku
?. - Składnia: pary klucz-wartość rozdzielone znakiem
&. - Mapowanie: każde pole w wiadomości z żądaniem, które nie jest częścią szablonu ścieżki adresu URL, jest mapowane na parametr zapytania.
- Najlepsze w przypadku: prostych typów (ciągi znaków, liczby całkowite, wyliczenia) i pól powtarzanych.
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 zmieniają 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żywane w przypadku operacji POST, PATCH i PUT.
- Miejsce docelowe: 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 protokole jest treścią.
- Najlepsze rozwiązanie 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 zgodnej z AIP-134 Update lub w operacji PATCH używane są obie te wartości.
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"
}
Najważniejsze różnice w skrócie
| Funkcja | Parametry zapytania | Treść żądania |
|---|---|---|
| Wskazówki dotyczące programu AIP | Używane do wyszukiwania, filtrowania i operacji odczytu. | Używany w operacjach zapisu. |
| Widoczność | Widoczne w historii przeglądarki i dziennikach serwera. | Ukryty w adresie URL. |
| Złożoność | Ograniczone do płaskich lub powtarzanych struktur. | Obsługuje głęboko zagnieżdżone obiekty JSON. |
| Kodowanie | Musi być zakodowany w formacie adresu URL (np. spacje stają się znakiem %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 uwzględnieniem tych warunków:
- 4-cyfrowy rok
YYYY - Wartości roku w zakresie 0000–9999
- Brak egzekwowania ograniczeń daty rozpoczęcia wynikających z normy ISO-8601 lub innej epoki.
Nagłówki
Wykonanie punktów końcowych interfejsu API Google Health wymaga użycia odpowiednich nagłówków i tokena dostępu. W przypadku żądań GET i POST zalecamy używanie tego nagłówka:
Authorization: Bearer access-token Accept: application/json
Indeks zadań interfejsu API
W tej sekcji znajdziesz indeks typowych zadań interfejsu Google Health API oraz przykłady każdego z nich.
Uzyskiwanie identyfikatora użytkownika Fitbita lub Google
Gdy użytkownik wyrazi zgodę za pomocą Google OAuth 2.0, odpowiedź tokena nie będzie zawierać identyfikatora użytkownika Fitbita ani Google. Aby uzyskać identyfikator użytkownika, wywołaj getIdentitypunkt końcowy. getIdentity
zwraca zarówno starszy identyfikator użytkownika Fitbita, jak i identyfikator użytkownika Google.
Zalecamy, aby po wyrażeniu przez nowego użytkownika zgody 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"
}Uzyskiwanie danych częściowych lub szczegółowych zebranych w ciągu dnia
Użyj listpunktu końcowego dla konkretnego typu danych, aby uzyskać dane śróddzienne lub szczegółowe zebrane w ciągu dnia w obsługiwanych przedziałach czasu dla tego 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"
}Uzyskiwanie uzgodnionego widoku danych interwałowych
Aby pobrać dane interwałów bez nakładających się rekordów lub konfliktów na wielu urządzeniach, wywołaj reconcilepunkt końcowy. Punkt końcowy reconcile automatycznie usuwa duplikaty nakładających się przedziałów w różnych partiach synchronizacji i na różnych urządzeniach rejestrujących, zwracając wiarygodny, ciągły strumień danych, który można wykorzystać do renderowania osi czasu aktywności i obliczania czasu trwania.
Więcej informacji o tym, dlaczego połączone urządzenia generują nakładające się przedziały, oraz porównanie działania list i reconcile znajdziesz w przewodniku po zarządzaniu danymi.
Poniższy przykład porównuje odpowiedź list (która zwraca oba nakładające się rekordy) z odpowiedzią reconcile (która rozwiązuje konflikt, zwracając wiarygodny rekord) w przypadku użytkownika z 2 nakładającymi się sesjami ćwiczeń:
Lista nieprzetworzona
GET https://health.googleapis.com/v4/users/me/dataTypes/exercise/dataPoints Authorization: Bearer access-token Accept: application/json
{
"dataPoints": [
{
"name": "users/111111256096816351/dataTypes/exercise/dataPoints/7797422996486764704",
"exercise": {
"interval": {
"startTime": "2026-09-03T11:20:00Z",
"endTime": "2026-09-03T11:50:00Z"
},
"exerciseType": "RUNNING"
}
},
{
"name": "users/111111256096816351/dataTypes/exercise/dataPoints/4389052750481144696",
"exercise": {
"interval": {
"startTime": "2026-09-03T11:00:00Z",
"endTime": "2026-09-03T11:30:00Z"
},
"exerciseType": "RUNNING"
}
}
]
}Uzgodniono
GET https://health.googleapis.com/v4/users/me/dataTypes/exercise/dataPoints:reconcile Authorization: Bearer access-token Accept: application/json
{
"dataPoints": [
{
"dataPointName": "users/111111256096816351/dataTypes/exercise/dataPoints/7797422996486764704",
"exercise": {
"interval": {
"startTime": "2026-09-03T11:20:00Z",
"endTime": "2026-09-03T11:50:00Z"
},
"exerciseType": "RUNNING"
}
}
]
}Proces uzgadniania rozwiązuje konflikty między sesjami przez usuwanie duplikatów i wybieranie wiarygodnego rekordu zamiast tworzenia sztucznego przedziału czasu (np. od 11:00:00Z do 11:50:00Z). Uzgodniona odpowiedź zwraca zwycięski punkt danych (7797422996486764704) z jego pierwotnym zarejestrowanym przedziałem (od 11:20:00Z do 11:50:00Z), zachowując integralność pomiarów telemetrycznych i danych tej sesji.
Filtruj dane
Aby pobrać określone podzbiory rekordów punktów danych spełniające kryteria takie jak przedział czasu, data lub czas obserwacji, użyj punktu końcowego list lub reconcile z parametrem filter.
Szczegółowe wytyczne, reguły formatowania, błędy weryfikacji i przykłady zapytań znajdziesz w przewodniku po filtrowaniu danych.
Filtrowanie według rodziny źródeł danych
Aby wyodrębnić lub zagregować dane z określonych typów źródeł (np. z fizycznych urządzeń do noszenia a wpisów ręcznych), użyj parametru dataSourceFamily.
Szczegółowe wytyczne, obsługiwane rodziny oraz przykłady żądań i odpowiedzi dotyczące parametrów reconcile, rollUp i dailyRollUp znajdziesz w sekcji Filtrowanie według rodziny źródeł danych w przewodniku Filtrowanie danych.
Filtrowanie danych według czasu rozpoczęcia przedziału czasu
Użyj punktu końcowego list z parametrem filter, aby filtrować dane według czasu cywilnego lub przedziału.
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
Użyj punktu końcowego list z parametrem filter, aby filtrować dane według czasu fizycznego obserwacji próbki.
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/123456789/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 i agregowanie według rodziny źródeł danych
Rodzina źródeł danych to logiczne zgrupowanie źródeł danych (takich jak zegarki, aplikacje mobilne czy wpisy ręczne). Umożliwia to wyodrębnianie lub agregowanie danych z określonych typów źródeł (np. z fizycznych urządzeń do noszenia a z wpisów ręcznych).
Punkty końcowe reconcile, rollUp i dailyRollUp obsługują parametr dataSourceFamily. Mechanizm przekazywania zależy od punktu końcowego:
| Punkt końcowy (metoda HTTP) | Mechanizm |
|---|---|
reconcile (GET) |
Przekaż dataSourceFamily jako parametr zapytania w adresie URL. |
rollUp (POST) |
Przekaż dataSourceFamily jako pole w treści żądania JSON. |
dailyRollUp (POST) |
Przekaż dataSourceFamily jako pole w treści żądania JSON. |
Obsługiwane rodziny źródeł danych
W tabeli poniżej znajdziesz obsługiwane wartości dataSourceFamily:
| Opcja | Opis |
|---|---|
users/me/dataSourceFamilies/all-sources |
Wartość domyślna. Zwraca punkty danych uzgodnione we wszystkich zarejestrowanych źródłach danych własnych i pochodzących od innych firm. W przypadku tej opcji zwracane będą dane aplikacji innych firm (np. kroki z zegarka, kroki z aplikacji innych firm, kroki z telefonu komórkowego i kroki wprowadzone ręcznie). |
users/me/dataSourceFamilies/google-wearables |
Obejmuje dane rejestrowane przez urządzenia śledzące Google i Fitbit (takie jak trackery Fitbit i zegarki Pixel Watch). Nie obejmuje danych rejestrowanych ręcznie ani danych szacowanych przez telefon. Użyj tej opcji, jeśli integracja wymaga surowych danych telemetrycznych z czujników rejestrowanych bezpośrednio przez urządzenie do noszenia. |
users/me/dataSourceFamilies/google-sources |
Obejmuje źródła własne Google i Fitbita. Obejmuje to dane z urządzeń śledzących aktywność, dane z Health Connect i wszystkie dane wprowadzone ręcznie w aplikacjach własnych (takich jak aplikacja Fitbit czy Google Fit). |
Aby uzyskać uzgodniony strumień danych z określonej rodziny źródeł danych, wywołaj punkt końcowy reconcile z parametrem zapytania dataSourceFamily.
Na przykład to żądanie GET pobiera dane o śnie zarejestrowane 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": ""
}Aby agregować punkty danych w określonym rozmiarze okna ograniczonym do konkretnej rodziny źródeł danych, wywołaj punkt końcowy rollUp i przekaż pole dataSourceFamily w treści żądania JSON.
To żądanie POST wysyła zapytanie o liczbę kroków z chodzenia w ciągu dnia w odstępach godzinowych (3600s), zagregowaną wyłącznie na podstawie danych z urządzeń do noszenia:
Żądanie
POST https://health.googleapis.com/v4/users/me/dataTypes/steps/dataPoints:rollUp
Authorization: Bearer access-token
Accept: application/json
{
"range": {
"startTime": "2026-07-29T00:00:00Z",
"endTime": "2026-07-29T23:59:59Z"
},
"windowSize": "3600s",
"dataSourceFamily": "users/me/dataSourceFamilies/google-wearables"
}Odpowiedź
{
"rollupDataPoints": [
{
"startTime": "2026-07-29T08:00:00Z",
"endTime": "2026-07-29T09:00:00Z",
"steps": {
"countSum": "1200"
}
},
{
"startTime": "2026-07-29T09:00:00Z",
"endTime": "2026-07-29T10:00:00Z",
"steps": {
"countSum": "3450"
}
}
]
}Aby agregować dzienne punkty danych dla określonej rodziny źródeł, wywołaj punkt końcowy dailyRollUp i przekaż pole dataSourceFamily w treści żądania.
Na przykład to żądanie oblicza dzienne podsumowania liczby kroków użytkownika, w tym wszystkie źródła własne Google i Fitbita (urządzenia do noszenia i wpisy ręczne):
Żą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": 7,
"day": 28
},
"time": {
"hours": 0,
"minutes": 0,
"seconds": 0,
"nanos": 0
}
},
"end": {
"date": {
"year": 2026,
"month": 7,
"day": 30
},
"time": {
"hours": 0,
"minutes": 0,
"seconds": 0,
"nanos": 0
}
}
},
"windowSizeDays": 1,
"dataSourceFamily": "users/me/dataSourceFamilies/google-sources"
}Odpowiedź
{
"rollupDataPoints": [
{
"civilStartTime": {
"date": {
"year": 2026,
"month": 7,
"day": 28
},
"time": {}
},
"civilEndTime": {
"date": {
"year": 2026,
"month": 7,
"day": 28
},
"time": {
"hours": 23,
"minutes": 59,
"seconds": 59
}
},
"steps": {
"countSum": "8430"
}
},
{
"civilStartTime": {
"date": {
"year": 2026,
"month": 7,
"day": 29
},
"time": {}
},
"civilEndTime": {
"date": {
"year": 2026,
"month": 7,
"day": 29
},
"time": {
"hours": 23,
"minutes": 59,
"seconds": 59
}
},
"steps": {
"countSum": "11245"
}
}
]
}Zbieranie punktów danych w określonym przedziale czasu
Użyj rollUp
punktu końcowego, aby zwrócić zagregowane punkty danych na podstawie okna w sekundach w zakresie datetime
na podstawie czasu fizycznego użytkowników (w UTC).
Podczas wywoływania punktu końcowego rollUp podaj treść żądania reprezentującą wymagany zakres czasowy i windowSize. Pamiętaj o tych wymaganiach dotyczących
windowSize:
- Minimalny rozmiar okna: czas trwania
windowSizemusi wynosić co najmniej 1 sekundę ("1s"). Czas trwania krótszy niż sekunda, zero lub ujemny zostanie odrzucony z błędem400 Bad Request(INVALID_ROLLUP_WINDOW). - Dopasowanie rozdzielczości pamięci: aby uniknąć nierównomiernego rozkładu zagregowanych danych w podzakresach, wybierz wartość
windowSize, która jest równa lub większa od rozdzielczości pamięci bazowej typu danych (np."60s"w przypadku 1-minutowych przedziałów). Więcej informacji znajdziesz w artykule Rozmiar okna zbiorczego i rozdzielczość pamięci bazowej.
Aby na przykład zsumować liczbę kroków w 1-minutowych odstępach czasu (60s):
Żą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": "60s"
}Odpowiedź
{
"rollupDataPoints": [
{
"startTime": "2026-02-17T17:55:00Z",
"endTime": "2026-02-17T17:56:00Z",
"steps": {
"countSum": "72"
}
},
{
"startTime": "2026-02-17T17:54:00Z",
"endTime": "2026-02-17T17:55:00Z",
"steps": {
"countSum": "85"
}
},
...
]
}Łączenie danych z jednego lub wielu dni
dailyRollUp
Punktu końcowego należy używać, gdy chcesz agregować dane z jednego lub wielu dni, czyli z windowSize. W treści żądania podaj zakres czasu cywilnego zamknięty-otwarty dla wymaganego przedziału. 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"
}
}
]
}Podział na grupy, gdy zakres nie jest wielokrotnością rozmiaru okna
Jeśli żądany zakres nie jest dokładną wielokrotnością wartości windowSize (lub windowSizeDays), ostatni przedział czasowy zostanie chronologicznie skrócony do górnego punktu końcowego zakresu i będzie obejmować okres krótszy niż rozmiar okna. Interfejs API akceptuje Twoją prośbę bez modyfikacji i nie wykonuje zaokrąglania, przesunięć czasowych ani interpolacji danych.
Aby objąć cały żądany zakres, interfejs API używa dzielenia w górę do obliczenia łącznej liczby okien agregacji:
Number of windows = ceiling(Range duration / Window size)
Każdy przedział zaczyna się kolejno od początku zakresu. Jeśli dodanie kolejnego pełnowymiarowego okna spowoduje przekroczenie żądanego czasu zakończenia, ostatnie okno zostanie przycięte (ograniczone) do czasu zakończenia zakresu.
Jak działa podział na grupy
Gdy wysyłasz żądanie dotyczące zbiorczych danych z zakresów, które nie są podzielne, interfejs API stosuje te reguły:
- Podział na przedziały rozpoczyna się na początku żądanego zakresu (
range.startTimelubrange.start) i przebiega dalej o rozmiar okna (windowSizelubwindowSizeDays). - Ostatni przedział czasowy jest ograniczony na końcu żądanego zakresu (
range.endTimelubrange.end), co oznacza, że obejmuje krótszy okres niż żądany rozmiar okna. - Zwrócone obiekty
RollupDataPointlubDailyRollupDataPointzawierają wyraźnie określone własne sygnatury czasowe rozpoczęcia i zakończenia, których możesz użyć do sprawdzenia rzeczywistego czasu trwania obciętego zasobu. - Interfejs API zwraca dane zbiorcze w kolejności odwrotnej do chronologicznej (najnowsze jako pierwsze), więc ostatni przedział chronologiczny (czyli obcięty) pojawia się jako pierwszy element (
index 0) na zwróconej liście.
Scenariusz: 12-minutowy zakres z 5-minutowym oknem
Załóżmy, że klient prosi o zestawienie danych z 12-minutowego zakresu z 5-minutowymwindowSize:
range.startTime:10:00:00range.endTime:10:12:00(łączny czas trwania: 12 minut)windowSize:5 minutes
12 minut nie jest wielokrotnością 5 minut (12 = 5 * 2 + 2), więc interfejs API akceptuje żądanie i oblicza liczbę przedziałów jako ceiling(12 / 5) = 3.
W ten sposób powstają 3 przedziały czasowe:
- Koszyk 1:
[10:00:00, 10:05:00)– czas trwania: 5 minut (pełne okno) - Kosz 2:
[10:05:00, 10:10:00)– czas trwania: 5 minut (pełny okres) - Kosz 3 (skrócony):
[10:10:00, 10:12:00)– czas trwania: 2 minuty (skrócony dorange.endTime)
Wpływ na wartości zagregowane
Ponieważ ostatni przedział ma krótszy czas trwania, w przypadku wskaźników addytywnych (takich jak suma lub liczba kroków) wartość w obciętym przedziale będzie niższa wyłącznie z powodu krótszego czasu trwania.
Jeśli użytkownik przez cały 12-minutowy okres będzie szedł w stałym tempie 100 kroków na minutę:
- Kosz 1 (10:00–10:05): 500 kroków (5 minut × 100 kroków/minutę)
- Kosz 2 (10:05–10:10): 500 kroków (5 minut × 100 kroków/minutę)
- Kosz 3 (10:10–10:12): 200 kroków (2 minuty × 100 kroków/minutę)
Przykładowa odpowiedź interfejsu API pokazująca kolejność
Interfejs API zwraca wyniki w odwrotnej kolejności chronologicznej, więc obcięty zasobnik pojawia się jako pierwszy element na liście zwróconej przez interfejs:
{
"rollupDataPoints": [
{
"startTime": "2026-08-20T10:10:00Z",
"endTime": "2026-08-20T10:12:00Z",
"steps": {
"countSum": "200"
}
},
{
"startTime": "2026-08-20T10:05:00Z",
"endTime": "2026-08-20T10:10:00Z",
"steps": {
"countSum": "500"
}
},
{
"startTime": "2026-08-20T10:00:00Z",
"endTime": "2026-08-20T10:05:00Z",
"steps": {
"countSum": "500"
}
}
]
}
Rozmiar okna zbiorczego i rozdzielczość pamięci bazowej
Punkt końcowy rollUp akceptuje dowolną wartość windowSize o wartości co najmniej 1 sekundy, ale różne typy danych rejestrują i przechowują pomiary z różnymi częstotliwościami próbkowania lub w różnych przedziałach czasowych w pamięci bazowej. Na przykład dane dotyczące aktywności fizycznej rejestrowane przez urządzenia do noszenia, takie jak steps, distance, active-minutes i active-energy-burned, są zwykle rejestrowane w 1-minutowych (60s) odstępach czasu.
Podczas agregowania typów danych interwałów punkt końcowy rollUp umieszcza każdy zarejestrowany punkt danych w zasobniku zawierającym startTime tego punktu. Interfejs API nie dzieli, nie interpoluje ani nie rozprowadza danych interwałowych między zasobniki podinterwałów.
Jeśli określisz windowSize mniejszy niż interwał przechowywania danych bazowych (np. poprosisz o 10-sekundowe okno dla steps przechowywanych w interwałach 1-minutowych):
- Pierwszy podzakres pasujący do przedziału
startTime(np.10:00:00–10:00:10) otrzymuje całą skumulowaną liczbę z minuty (np. wszystkie 100 kroków zarejestrowanych w tej minucie). - Pozostałe podzasobniki w tej samej minucie (
10:00:10–10:00:20,10:00:20–10:00:30itd.) nie otrzymują żadnych punktów danych, ponieważ w tych przedziałach nie rozpoczyna się żaden interwał.
W efekcie otrzymujemy „skokowe” dane, w których wartość całego interwału jest skoncentrowana w pierwszym podoknie.
Aby uzyskać równomiernie rozłożone i znaczące wartości zagregowane, zawsze ustawiaj parametr windowSize na czas trwania równy lub większy niż rozdzielczość pamięci masowej bazowego typu danych docelowych (np. 60s lub większy w przypadku steps). Rozdzielczość pamięci masowej i minimalne zalecane okno podsumowania dla każdego typu danych znajdziesz w dokumentacji typów danych interfejsu Google Health API.
Aktualizowanie danych dotyczących zdrowia użytkownika
Użyj patchpunktu końcowego, aby zaktualizować dane dotyczące zdrowia użytkownika.
Punkt końcowy patch aktualizuje istniejący rekord na podstawie identyfikatora podanego w adresie URL żądania. Podaj identyfikator wcześniej wstawionego punktu danych. Interfejs API zastępuje istniejący rekord.
Znaczniki czasu interwału punktu danych (startTime i endTime) mogą być też aktualizowane przez właściciela rekordu lub propagowane z platform nadrzędnych, takich jak Health Connect. Szczegółowe informacje o możliwości zmiany sygnatur czasowych znajdziesz w przewodniku po zarządzaniu danymi. Przykład aktualizowania sygnatur czasowych interwałów znajdziesz w artykule Aktualizowanie sygnatur czasowych interwałów dla istniejących danych.
Kiedy używać identyfikatora punktu danych
Identyfikator punktu danych jest niezbędny w tych sytuacjach:
- Aktualizacje kierowane: aby zaktualizować konkretny pomiar, podaj jego identyfikator w żądaniu
patch. - Usuwanie: zachowanie identyfikatora umożliwia aplikacji późniejsze usunięcie rekordu za pomocą
batchDeletepunktu końcowego.
Oto przykład, w którym użytkownik aktualizuje odczyt tkanki tłuszczowej na wadze „HumanScale” firmy „Scales R Us”. Nowy odczyt tkanki tłuszczowej użytkownika to 20% – data: 10 marca 2026 r.:
Żądanie
PATCH https://health.googleapis.com/v4/users/me/dataTypes/body-fat/dataPoints/1234567890
Authorization: Bearer access-token
Content-Type: application/json
{
"name": "users/me/dataTypes/body-fat/dataPoints/1234567890",
"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/123456789/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
}
}
}Aktualizowanie sygnatur czasowych interwałów w przypadku dotychczasowych danych
Aby zaktualizować wartość startTime lub endTime istniejącego punktu danych interwału, wyślij żądanie PATCH do identyfikatora URI zasobu punktu danych. Pola rekordu może modyfikować tylko jego pierwotny twórca lub właściciel. Aplikacje nie mogą edytować punktów danych, których nie utworzyły.
Więcej informacji o tym, czy sygnatury czasowe mogą ulegać zmianom, o aktualizacjach z Health Connect i o implikacjach związanych z pamięcią podręczną znajdziesz w przewodniku po zarządzaniu danymi.
Ten przykład pokazuje, jak aplikacja właściciela aktualizuje sygnatury czasowe interwałów
istniejącego dziennika nawodnienia za pomocą punktu końcowego patch:
Żądanie
PATCH https://health.googleapis.com/v4/users/me/dataTypes/hydration-log/dataPoints/4093039283164890826
Authorization: Bearer access-token
Content-Type: application/json
{
"hydrationLog": {
"interval": {
"startTime": "2026-09-03T10:05:00Z",
"endTime": "2026-09-03T10:19:59Z"
},
"amountConsumed": {
"milliliters": 350
}
}
}Odpowiedź
{
"done": true,
"response": {
"@type": "type.googleapis.com/google.devicesandservices.health.v4.DataPoint",
"name": "users/111111256096816351/dataTypes/hydration-log/dataPoints/4093039283164890826",
"hydrationLog": {
"interval": {
"startTime": "2026-09-03T10:05:00Z",
"endTime": "2026-09-03T10:19:59Z",
"civilStartTime": {
"date": {
"year": 2026,
"month": 9,
"day": 3
},
"time": {
"hours": 10,
"minutes": 5
}
},
"civilEndTime": {
"date": {
"year": 2026,
"month": 9,
"day": 3
},
"time": {
"hours": 10,
"minutes": 19,
"seconds": 59
}
}
},
"amountConsumed": {
"milliliters": 350
}
}
}
}Zapisywanie produktu spożywczego
Aby zarejestrować produkt spożywczy, wyślij żądanie POST do punktu końcowego nutrition-log dataPoints. Treść żądania zawiera element 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/123456789/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
Użyj batchDeletemetody, aby usunąć tablicę danych użytkownika z aplikacji Fitbit.
Oto przykład sytuacji, w której użytkownik wcześniej zarejestrował pomiar tkanki tłuszczowej na wadze, ale chce usunąć ten zapis. Używanie user-id i data-point-id z pierwotnej funkcji przyczepów:
Żą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/123456789/dataTypes/body-fat/dataPoints/1234567890"
]
}Odpowiedź
{
"done": true,
"response": {
"@type": "type.googleapis.com/google.devicesandservices.health.v4main.BatchDeleteDataPointsResponse"
}
}Znajdowanie informacji o urządzeniu
Użyj punktu końcowego list, aby pobrać listę urządzeń sparowanych z kontem użytkownika. Obejmuje to informacje o modelu urządzenia (deviceVersion) i ostatniej synchronizacji z aplikacją mobilną Google Health (lastSyncTime).
Konfiguracja listy i informacje o 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 z dowolnego okresu, w którym były one rejestrowane. Interfejs API nie nakłada żadnych ograniczeń na ilość danych historycznych, które może wykorzystywać Twoja aplikacja.
Wykonywanie zapytań dotyczących danych historycznych podlega jednak standardowym limitom częstotliwości. Aby zarządzać stabilnością systemu i zapobiegać nadmiernym rozmiarom pakietów danych, interfejs Google Health API używa automatycznego stronicowania z rozmiarami stron dostosowanymi do konkretnych punktów końcowych. Pamiętaj o tych granicach i sposobie działania:
- Automatyczny podział na strony: jeśli zapytanie dotyczy długiego okresu danych, interfejs API zwróci tylko pierwszą stronę wyników do limitu rozmiaru strony dla danego punktu końcowego wraz z parametrem
nextPageToken. Aby poprosić o kolejne strony, musisz użyć parametrunextPageToken. - Zmienne rozmiary stron: limity ograniczające zależą od punktu końcowego i typu danych. W przypadku większości typów danych rozmiar strony jest ograniczony 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 zwróci na pierwszej stronie tylko 25 sesji snu. - Ograniczenia zakresu dat w przypadku scalania danych: w przypadku punktów końcowych scalania i agregacji danych (np.
rollUpidailyRollUp) zakresy dat zapytań są ograniczone w zależności od typu danych:- Maksymalny zakres 14 dni w przypadku usług
calories-in-heart-rate-zone,heart-rate,active-minutesitotal-calories. - Maksymalny zakres 90 dni w przypadku wszystkich innych rodzajów danych zbiorczych.
- Maksymalny zakres 14 dni w przypadku usług
W zależności od ilości danych historycznych, których potrzebuje Twoja aplikacja, pobranie całego zbioru danych będzie wymagać sekwencyjnego przechodzenia przez strony. Pamiętaj o tym podczas projektowania procesu synchronizacji danych w aplikacji.
Aby zapewnić optymalną skuteczność i uniknąć błędów interfejsu API, podczas wysyłania zapytań o dane historyczne postępuj zgodnie z tymi wytycznymi:
Synchronizacja danych etapami (gorące ładowanie 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: przekazywanie starszych danych historycznych do asynchronicznej kolejki o niższym priorytecie lub procesu w tle po wyrenderowaniu głównego interfejsu.
Dzielenie zapytań na potrzeby agregacji
- Ponieważ punkty końcowe zbiorczych i dziennych danych zbiorczych wymuszają maksymalny zakres dat (14 lub 90 dni w zależności od typu danych), musisz podzielić duże zapytania o historyczne dane zbiorcze na mniejsze, kolejne przedziały w tych limitach.
- Bezpiecznie grupuj lub sekwencjonuj te zapytania, aby zachować limity współbieżności i utrzymywać stałe wskaźniki postępu interfejsu.
Wykorzystywanie wstępnie zagregowanych podsumowań
Zmień strukturę paneli ogólnych i wykresów trendów, aby korzystać z wstępnie zagregowanych punktów końcowych podsumowania (np. DailyRollUpDataPoints). Znacznie zmniejszy to obciążenie obliczeniowe backendu i czas przesyłania danych do klienta.
Odporna obsługa błędów (inteligentne ponawianie)
- W przypadku przekroczenia ograniczania liczby żądań (
429 Too Many Requests) i limitów czasu bramy serwera (504 Gateway Timeout) stosuj ścisłe wzrastający czas do ponowienia. Nigdy nie ponawiaj od razu prób wysyłania dużych, nieudanych ładunków. Natychmiastowe ponawianie prób zwiększa przeciążenie backendu i pogarsza działanie systemu.