Como lidar com alterações de back-end para versões mais antigas de aplicativos móveis

Sempre que temos um novo recurso que queremos adicionar a um aplicativo existente, como desenvolvedor web estamos acostumados a atualizar o frontend e o backend simultaneamente. E então implantamos as mudanças no ambiente de produção e encerramos o dia.

Porém, no caso de aplicativos móveis, o mesmo conceito nem sempre é aplicável. Porque nem todo mundo atualizará automaticamente o aplicativo. Conseqüentemente, as novas alterações no código de back-end podem não funcionar conforme o esperado nas versões mais antigas do aplicativo móvel. Qual é a maioria dos usuários após um novo lançamento.

Digamos que temos um aplicativo que permite aos usuários controlar suas despesas mensais. Temos um aplicativo nativo React para obter os inputs dos usuários e um backend que armazena as despesas em um banco de dados. E a seguir está o formato JSON que usamos para nos comunicarmos com o backend:

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}

Supondo que temos um aplicativo React Native que está consumindo a API, mostraremos as despesas em uma lista. Assim:

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>

Mas e se agora quisermos adicionar um recurso que permita aos usuários também armazenar seus rendimentos? Para conseguir isso, precisamos atualizar o código backend para armazenar também as receitas no banco de dados. E ao recuperar os dados, precisamos enviá-los de volta no seguinte formato JSON:

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}

Portanto, o aplicativo móvel terá que atualizar o código para lidar com o novo formato JSON.

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>

Mas nas versões mais antigas do aplicativo móvel, o código ainda usará o antigo formato JSON. Portanto, o aplicativo irá travar. E o mesmo se aplica ao salvar os dados no backend. As versões mais antigas do aplicativo móvel não poderão salvar os dados no novo formato JSON caso tenhamos um validador que verifique o formato JSON antes de salvá-lo no banco de dados. Mas aqui falaremos apenas sobre o formato da resposta. Temos certeza de que você poderá cuidar da parte de “salvar condicionalmente no banco de dados” sozinho, uma vez que conheça o truque.

Para resolver esse problema, podemos retornar condicionalmente o antigo formato JSON para as versões mais antigas do aplicativo móvel. E retorne o novo formato JSON para as versões mais recentes do aplicativo móvel. Mas como o servidor back-end saberia qual versão do aplicativo móvel o usuário está usando? É aí que entra a biblioteca chamada `react-native-device-info`. Usando esta biblioteca podemos obter a versão do aplicativo móvel e enviá-la para o servidor backend usando um cabeçalho personalizado `MobileAppVersion`. No backend, podemos verificar se o cabeçalho `MobileAppVersion` está presente e é maior ou igual à versão do aplicativo móvel que queremos oferecer suporte. Se for, podemos retornar o novo formato JSON, caso contrário, podemos retornar o antigo.

Se você estiver usando apisauce (que é recomendado), você pode definir os cabeçalhos assim:

RELACIONADO:O aplicativo Weather da Apple acaba de receber 13 novos recursos e alterações na última atualização de software do iPhone

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())

ou se você não estiver usando o apisauce, você pode definir os cabeçalhos manualmente assim:

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...

Então, no código de back-end, você pode retornar condicionalmente a resposta com base na versão do aplicativo.

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})

ou se você estiver usando Python com Django você pode fazer algo assim:

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':[...]})