Hoe om te gaan met backend-wijzigingen voor oudere versies van mobiele apps

Wanneer we een nieuwe functie hebben die we aan een bestaande app willen toevoegen, zijn we als webontwikkelaar gewend om zowel de frontend als de backend tegelijkertijd te updaten. En dan implementeren we de wijzigingen in de productieomgeving en houden we er mee op.

In het geval van mobiele apps is hetzelfde concept echter niet altijd van toepassing. Omdat niet iedereen de app automatisch zal updaten. Daarom werken de nieuwe wijzigingen in de backend-code mogelijk niet zoals verwacht in de oudere versies van de mobiele app. Dat is de meerderheid van de gebruikers na een nieuwe release.

Laten we zeggen dat we een app hebben waarmee gebruikers hun maandelijkse uitgaven kunnen bijhouden. We hebben een native React-app om de input van de gebruikers te krijgen en een backend die de uitgaven in een database opslaat. En het volgende is het JSON-formaat dat we gebruiken om met de backend te communiceren:

1{2    data:[3{4"id":1,5"amount":100,6"date":"2021-01-01",7"category":"Food",8"subcategory":"Groceries",9"description":"Bought groceries for the month",10},11{12"id":2,13"amount":200,14"date":"2021-01-02",15"category":"Transportation",16"subcategory":"Gas",17"description":"Filled up the gas tank",18}19]20}

Ervan uitgaande dat we een React Native-app hebben die de API gebruikt, tonen we de uitgaven in een lijst. Zoals dit:

1<View>2{result?.data?.map((expense)=>(3<View>4<Text>{expense.amount}</Text>5<Text>{expense.date}</Text>6<Text>{expense.category}</Text>7<Text>{expense.subcategory}</Text>8<Text>{expense.description}</Text>9</View>10))}11</View>

Maar wat als we nu een functie willen toevoegen waarmee de gebruikers ook hun inkomen kunnen opslaan? Om dat te bereiken moeten we de backend-code bijwerken zodat ook de inkomens in de database worden opgeslagen. En terwijl we de gegevens ophalen, moeten we de gegevens terugsturen in het volgende JSON-formaat:

1{2    data:{3        expenses:[4{5"id":1,6"amount":100,7"date":"2021-01-01",8"category":"Food",9"subcategory":"Groceries",10"description":"Bought groceries for the month",11},12{13"id":2,14"amount":200,15"date":"2021-01-02",16"category":"Transportation",17"subcategory":"Gas",18"description":"Filled up the gas tank",19}20],21        incomes:[22{23"id":1,24"amount":10000,25"date":"2021-01-01",26"category":"Salary",27"subcategory":"Full-time",28"description":"Received salary for the month",29},30{31"id":2,32"amount":2050,33"date":"2021-01-02",34"category":"Freelance",35"subcategory":"Writing",36"description":"Received freelance payment for the month",37}38]39}40}

Daarom zal de mobiele app de code moeten bijwerken om het nieuwe JSON-formaat te verwerken.

1<View>2-{result?.data?.map((expense)=>(3+{result?.data?.expenses?.map((expense)=>(4<View>5<Text>{expense.amount}</Text>6<Text>{expense.date}</Text>7<Text>{expense.category}</Text>8<Text>{expense.subcategory}</Text>9<Text>{expense.description}</Text>10</View>11))}12</View>

Maar in de oudere versies van de mobiele app gebruikt de code nog steeds het oude JSON-formaat. De app crasht dus. En hetzelfde geldt voor het opslaan van de gegevens in de backend. De oudere versies van de mobiele app kunnen de gegevens niet in het nieuwe JSON-formaat opslaan als we een validator hebben die het JSON-formaat controleert voordat deze in de database wordt opgeslagen. Maar hier zullen we het alleen hebben over het antwoordformaat. We zijn er zeker van dat u het gedeelte 'Voorwaardelijk opslaan in de database' zelf kunt afhandelen zodra u de truc kent.

Om dit probleem op te lossen kunnen we voorwaardelijk het oude JSON-formaat retourneren voor de oudere versies van de mobiele app. En retourneer het nieuwe JSON-formaat voor de nieuwere versies van de mobiele app. Maar hoe weet de backend-server welke versie van de mobiele app de gebruiker gebruikt? Dat is waar de bibliotheek met de naam `react-native-device-info` in beeld komt. Met behulp van deze bibliotheek kunnen we de versie van de mobiele app ophalen en deze naar de backend-server sturen met behulp van een aangepaste header `MobileAppVersion`. In de backend kunnen we controleren of de header `MobileAppVersion` aanwezig is en groter is dan of gelijk is aan de versie van de mobiele app die we willen ondersteunen. Als dit het geval is, kunnen we het nieuwe JSON-formaat retourneren, anders kunnen we het oude retourneren.

Als je apisauce gebruikt (wat wordt aanbevolen), kun je de headers als volgt instellen:

VERWANT:Apple's weerapp heeft zojuist 13 nieuwe functies en wijzigingen gekregen in de nieuwste iPhone-software-update

1import DeviceInfo from"react-native-device-info"2
3...4setAllHeaders(value?: string, appVersion?: string){5    api.apisauce.setHeader("Authorization",`Bearer ${value}`)6    api.apisauce.setHeader("MobileAppVersion", appVersion ||"")7}8...9
10setAllHeaders(token, DeviceInfo.getVersion())

of als je geen apisauce gebruikt, kun je de headers als volgt handmatig instellen:

1asyncfunctiongetData(url: string,appVersion: string){2const response =awaitfetch(url,{3headers:{4'Authorization':'Bearer Token',5'MobileAppVersion': appVersion ||""6}7})8const data =await response.json()9return data
10}11
12...13// get the data from the api (e.g. inside useEffect, or a button press)14const result =awaitgetData("https://api.example.com", DeviceInfo.getVersion())15...

Vervolgens kunt u in de backendcode het antwoord voorwaardelijk retourneren op basis van de appversie.

1const express =require('express')2const app =express()3
4app.get('/',(req, res)=>{5const appVersion = req.headers['MobileAppVersion']6if(appVersion && appVersion >='2.0.0'){// if the app version is 2.0.0 or higher7        res.json({data:{expenses:[...],incomes:[...]}})8}9else{10// if the app version is lower than 2.0.0, older response format11        res.json({data:[]})12}13})

of als je Python met Django gebruikt, kun je zoiets als dit doen:

1from django.http import JsonResponse
2
3classget_data(request):4defget(self, request):5        app_version = request.headers.get('MobileAppVersion','1.0.0')6if app_version and app_version >='2.0.0':7# if the app version is 2.0.0 or higher8return JsonResponse({'data':{expenses:[...], incomes:[...]}})9else:10# if the app version is lower than 2.0.0, older response format11return JsonResponse({'data':[...]})