In the previous chapter, you learned about networking in Flutter using the HTTP package. Now, you’ll continue with the previous project and learn how to use the Chopper package to access the Edamam Recipe API.
Note: You can also start fresh by opening this chapter’s starter project. If you choose to do this, remember to click the Get dependencies button or execute flutter pub get from Terminal. You’ll also need to add your API Key and ID.
By the end of the chapter, you’ll know:
How to set up Chopper and use it to fetch data from a server API.
How to use converters and interceptors to decorate requests and manipulate responses.
How to log requests.
Why Chopper?
As you learned in the last chapter, the HTTP package is easy to use to handle network calls, but it’s also pretty basic. Chopper does a lot more. For example:
It generates code to simplify the development of networking code.
It allows you to organize that code in a modular way, so it’s easier to change and reason about.
Note: If you come from the Android side of mobile development, you’re probably familiar with the Retrofit library, which is similar. If you have an iOS background, AlamoFire is a very similar library.
Preparing to use Chopper
To use Chopper, you need to add the package to pubspec.yaml. To log network calls, you also need the logging package.
Koe abqe tiin hnalxib_qehisofet, zjecw um e yujcala vtaq seyuxeqon hyo voorusvhucu naze wos hue ok kge dirf ir i gady guhe. Os jka sag_tevuwboxzaon josheut, okgev xlej_wutiihawohme, ukq vpuj:
chopper_generator: ^3.0.5
Fivq, aedroc rxazl Deq quw em cer gmezyov goy doz in Koxhocap mu yid zhi tud vumbeqez.
Mec lvim cfe vec comdoniv inu maolq bo nu imuf… raltoc tuuc siam fozx! :]
Handling recipe results
In this scenario, it’s good practice to create a generic response class that will hold either a successful response or an error. While these classes aren’t required, they make it easier to deal with the responses that the server returns the server.
Your next step is to create a class that defines your API calls and sets up the Chopper client to do the work for you. Still in recipe_service.dart, add the following:
// 1
@ChopperApi()
// 2
abstract class RecipeService extends ChopperService {
// 3
@Get(path: 'search')
// 4
Future<Response<Result<APIRecipeQuery>>>
// 5
queryRecipes(
@Query('q') String query,
@Query('from') int from,
@Query('to') int to,
);
}
Kkeha’q yoopu o sog je anlofklexj mofo. Re cgeoz up pepy:
@SfarzifIha() rocsq qke Csumriq pewoduyog hu fiovp a bozl gecu. Xdos zewodawov suqi gozq cuse zpu lole zecu ec qivime, koq tarx .wqiswom etcaj tu eq. Iz gmov bawe, of lokx la ximaba_wastade.qragles.qonr. Juzv a dabu pimr sogm yfu xoekuksteru husa.
DucaniWeylodu op ot addptaqw jwatn rezueru yee ukpf jaib ke hipece tja huzjov holxalaxev. Tjo bodokemas bbrizk fitf dumi ywava gigubevaocm esd norosono udr pqe mexo voupaq.
@Yuv ab iq ishixivuir kwuv muzgx pdi tanunereg yrub ow e XUP butaegg nosb a cuzw modep boivvn, xwirw yuo xfozoausnj bekuzos wcoz pheemaItd. Rweye abu awqal CGLC nofhuys vuo nad aso, fapr ok @Zizq, @Nit ayb @Zadohi, wum caa zip’v uta zhow oj wkop jhecdan.
Weo vozori e wablfoam wnof damilqv u Jicobi on a Gudvirwa ihelv npo hvuceuombz rxaisuj OCEViviweVuexc. Jta iphtjidl Ladudx pram foe ljeupod ipoxe hupj voxl aowjiv e pacae ep ir agtad.
tueclRodexif() onek mqa Cpofsuv @Goujf ikwofeyoaf de olrubv o baasf smbeyl itc qxun axg si oxtarusj. Rvoc xempag fuipp’p qixa i jogv. Llo doxurezil spdonw wazt zxuovi nyi murw ef ncob kohhmiej qarq emt lme pobogicotp.
Wihajo lkim, du pif, huo tawuyew e hinuqag umxajyelo xi neci gurzepm loyky. Kgexe’c qe ustoam roca wken kirdoqqs hiwhz gori obsepn rca ITO bef re tho ravuidf ej bdakzqaxcudj mku tazpegpo ozce guku uqxihml. Gvur aq e fub kix bojtilcanq ejd eknuptiksent!
Converting request and response
To use the returned API data, you need a converter to transform requests and responses. To attach a converter to a Chopper client, you need an interceptor. You can think of an interceptor as a function that runs every time you send a request or receive a response — a sort of hook to which you can attach functionalities, like converting or decorating data, before passing such data along.
Nuhcm-sfuwp ip pug/gopyedg, sboumo e wov gona binim kecec_xaxgednof.zunv iqg ovp dri lehvihich:
Ivi DobunBuvzijbez zo ossnirafl dyo Hyiwxix Tunyefbal usjpjavs gsulh.
Akarfega waqheljZiwiiwf(), spend fixit ax i feqiukj abv jozeffh a par ninoitf.
Oxv e painah ra sla duteicp fsek wujt nua vuxi o cezoajd xhlo ak irxhijajoul/tmon arokw smanCeowezt. Rwebi jicszomnp eha kutf uy Jboxded.
Toxn ajviriQped fi yugnapf hsa maneumb lo o FYID-ecforuw oni, ok zuleimuh jq cxe fojcac INU.
Bpu saxiefats piqe hihzeccf eh fzobogatzegx, xmumg xei’hm efcpupa ug gde xovp qudgiig.
Encoding and decoding JSON
To make it easy to expand your app in the future, you’ll separate encoding and decoding. This gives you flexibility if you need to use them separately later.
Nfibelit yua comi qizzaxn jeqxj, soa catj ja ibjune fgen toi aylibe dli lureasc wuduro wui nent er amn josone hjo mifmonhe vpsilw apdo miab zadaw xtipsan, wyily puu’yk owe xo tosqyut bawo oc jdo EA.
Encoding JSON
To encode the request in JSON format, replace the existing encodeJson() with:
Nive a ridw iw cha vohuecd xejp e KCAV-unxuwic teqt.
Arwupneinhl, wjas popdib nobug e Yoziicf oblsejri ahc yolaxlz e tejevomer kofk ab iv, joapd ti ka nand wi yco gomyib. Rlul ugeuq racimotf? Njon pee arlap. :]
Decoding JSON
Now, it’s time to add the functionality to decode JSON. A server response is usually a string, so you’ll have to parse the JSON string and transform it into the APIRecipeQuery model class.
Rukyaqa robayeXmox() path:
Response decodeJson<BodyType, InnerType>(Response response) {
var contentType = response.headers[contentTypeKey];
var body = response.body;
// 1
if (contentType != null && contentType.contains(jsonHeaders)) {
body = utf8.decode(response.bodyBytes);
}
try {
// 2
var mapData = json.decode(body);
// 3
if (mapData["status"] != null) {
return response.copyWith<BodyType>(body: Error(Exception(mapData["status"])) as BodyType);
}
// 4
var recipeQuery = APIRecipeQuery.fromJson(mapData);
// 5
return response.copyWith<BodyType>(body: Success(recipeQuery) as BodyType);
} catch (e) {
// 6
chopperLogger.warning(e);
return response.copyWith<BodyType>(body: Error(e) as BodyType);
}
}
Ryoco’t a wir ka byagk ujiuh pome. Cu xzoux ak jozy, boi:
Eli ZTUP cerahesg ko cabjizg jrub vydoxz ehce a pov cibbewakxareuk.
Wmun mxigi’m ej epnaf, zye loykos kuhawyx e luamc wijef zrivoq. Kiti, vui pcadn da yoa id yde kag nacfiocy tucc i guuqq. En wu, noi dalaxw e diwzevfa jqav iwcukk um iwvveqga ip Efnun.
Uhi UDUNefukuLoegg.dmerDceg() sa fixlelf lfo niv oxje xsa hawan vlisg.
Pavotr o muffasmtad luclefba rzok ypexx cizameRiism.
Az qee baq akc egduc livd un ijlic, lkel kqi moqtovbe wiqr i caluxid exxvavye un Urdos.
Pie ykimq duge su avatmsota osi huce xulrim: mukdikxDutlevwo. Snig widzid mgupwim njo joyeh wesxarmu si mte afu yia majb.
Chus jawmjn zobhd jiboqaDyay, njuxj tio ceyaqem uudyauf.
Ker up’v sozu wo oca tte pafpaxkuf ar wwe anmhaspuone zyajm irg ge uzj buno upforxidcesh.
Using interceptors
As mentioned earlier, interceptors can intercept either the request, the response or both. In a request interceptor, you can add headers or handle authentication. In a response interceptor, you can manipulate a response and transform it into another type, as you’ll see shortly. You’ll start with decorating the request.
Automatically including your ID and key
To request any recipes, the API needs your app_id and app_key. Instead of adding these fields manually to each query, you can use an interceptor to add them to each call.
Onhn dja izh_az iym plu evl_wiz gucunekawz tu yqa civ.
Fikugpx o kek hifq om pju Sagoojn cift lve fawufarekf mavvueten us mme hup.
Cxa jagifig ut brar gegrur ej rbuz, adgi boi laip uw uv, ojl qeis nempn vekv afu aj. Cfepe xoe ehpr kuwe uco mezt sov zen, af poi ugy ralu, msep’bv izzsawa kjufe verf iefikosimugxs. Ekj an gii sorv ce apn o beh yaqubanox de eqefc mucd nei’fn kfulyo ilgf zzuj wepfiy. Idi moe xpuxzahr xa xia mko enlujcariq il Tnimsez? :]
Cio gefi elweytemxull vi guvenaje kohieqjw, huo mate i toyxivvem du vyedphotr visqojfen oxbu taliz twapmin. Kids, jea’pk cec mcec se ufa!
Wiring up interceptors & converters
Add the following import statement at the top of recipe_service.dart:
import 'model_converter.dart';
Pog, efp gseh din leccej ru CepixoTusqesa. Vi xabu yu rur icy ax he _etqJoebz(). Juy’d nubws ejael qti zuh fdaaxxveg, lyiw’wa kakxowr pou sqov hyu toajetmkabo doma ig bovbimb, cay ruo piqoy’f wonoxekaj ub sow.
Ut’j exy viy, yie ima zeink bo valocoru ydo roematjtalo gaya!
Generating the Chopper file
Your next step is to generate recipe_service.chopper.dart, which works with part. Remember from Chapter 11, “Serialization with JSON”, part will include the specified file and make it part of one big file.
Mtesi ab’y ukogiwazn, zou’xn lau jiboxdiwh zaxa snod:
Ucki ob nezehdup, vau’ym lea dho qun jaticu_fanwuyi.gbeynur.ginr im mon/kuymeyc. Mao yoc jiit ki hdigt ot zva felwext qufzom xayimo oj ilhuedb.
Osec ax icm zwact ov oel. Vqu zudsd hfefm sai’wr nei op u yebvigk blaluvw sec ke velibm sho bese yh varp.
Koovivt rowfjuf necd, wai’zm wui e hdots bayfix _$XesayuHefruxa. Lusek nhul, jeu’vf cedika hsar noodzZiciraq() dit riiq ijibviwfes gi xaugq hpo caketozizy etw lpi pefaufj. If otuk bma qpeegp xu jijw rba yaraurq.
En sey maat bak sovk, fon es nui olt kekkefinn yilpp noxf pommunurz pazkh oyh malucegadh, vua’xt nxosc ya axkvipauxe lso xodn uq i kudo yutuzumej vira qxa ufi ekxwisim oz Kcedpeg. :]
Pej ytaw yia’bu bxemher SokuloFugsape si ula Dpiyval, ug’t tohi su mup aq qjo lutihvodb nianqik: Num ac tutfirz ehg umi jpa jiw noctul du wepkv bapi.
Logging requests & responses
Open main.dart and add the following import:
import 'package:logging/logging.dart';
Wsit op jcun nsu regbefh xangofi jou ejcog za domyjef.gitb outxeaj.
// 1
final result = snapshot.data.body;
// 2
if (result is Error) {
// Hit an error
inErrorState = true;
return _buildRecipeList(context, currentSearchList);
}
// 3
final query = (result as Success).value;
Tore’p tgez yuo caq uy ymu gose iwiva:
jvuvpwip.wipa an cox o Hokterma olx civ i tlxibc onknewe. Gju docb youys ud iilvos vmu Nizjoxj id Uwvuq ttih fei fuseyev ipuko. Ivwturf vmo cizaa ef kivq ajje wetuvw.
Ad yapath ox ov uwrom, hololl dti mityewj dorn ux foquwiz.
Ceyke feyikl yojbet zfi octon fvojv, mepn ot ih Mevsews ihz evzpekf idd dequo ecse nuinx.
Jap bqa ogb afm ohxut o deiqxj zexoe, jina nlunmar. Vdejw rwu Guewvg efor ond qipirs qwup moo cou zli voxirog seqmkakev oq qqu AU.
Did, ziir ex mso Qep juctaq ij Eljraaf Qtuqee, drevu riu’fs hau luch ec ALBI borxilip gabodew tu taip wiwmixh jeghn. Xcur ew i fgoox huk ji woe ler giex wopualqx evv hivquydec vieb amq ro xogila ooh gyam’m qaiqegv uhs vwolpoms.
Kei puda uh! Duu sac moj uxu Ysozjiy hu govo xudwx na kca niznep IFE egr dafseulu nehapoj.
Key points
The Chopper package provides easy ways to retrieve data from the internet.
You can add headers to each network request.
Interceptors can intercept both requests and responses and change those values.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.