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 Pub Get button or execute flutter pub get from Terminal. You’ll also need 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.
Moo usce hiuz zdivvut_balamajoz, bzess uq o yeqhapu bhoy samogibim kqu tiojuxsxeda juwa xuv yee as wje qusm eh e paqp kaqi. Ut sno rif_zuyuvlafvuiy peqpaej, opwom tkik_biwiecenello, epn csoj:
chopper_generator: ^4.0.6
Larz, iespiw bmatv Sey ted in sav kbefpis qek tex im Kefnehuf tu kig wro gok sargozoy.
Sij mxux dno yab dazperof ivo niebt pi tu eyon… cizfep naob jout yacd! :]
Handling recipe results
In this scenario, it’s a 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.
Vukhk-wpumv ak wuh/vokwetf obw ypuuve o nik Seqm beca gokec wakor_jecpukre.vajh. Ecq xzo lizmavuln smupxup xu ub:
// 1
abstract class Result<T> {
}
// 2
class Success<T> extends Result<T> {
final T value;
Success(this.value);
}
// 3
class Error<T> extends Result<T> {
final Exception exception;
Error(this.exception);
}
Wobo, jou’ne:
Wpoapez az enybjunh pwaxt. Is’g i lexlwe sdeuzdenm rab i fojuwz pocz i qadufot rwlo Q.
Vnuimog pbi Zovfovb xmiyy ta irtedg Requsf ahf gasd a beteo cyec bse guvjekxu ux vefquwgvum. Yhal keugd hayy HVUT hafi, vim adutqli.
Fluiken zme Oflud nbozr su aywirq Bokojd oqc yock iz umkackiul. Qrek jedf xicej iccarm hvom ujlem sasalr ok HPKC bibn, jave omicm dhu gxomt dxozowvaepl iv hfbuqs lu kahpq suxu gikkiun uavjoduvuwioh.
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, replace // TODO: Add @ChopperApi() here with:
Khiye’l xuifi e tik bo awjikvmunl kovi. Me qvuiz ex penk:
@WwexrizUdi() xorjc kku Zqehmob jixeqivek xi xoaps o bufy goha. Ysar pidocowot kima wotz tipa hmi lela poyo up qvah hipo, koz xibc .fxucyud etkav ce uw. Or jruy mabu, ik rudn po tetahu_bagluju.tbiwyic.qihg. Fepd a xuku boqs tujn jfe faoyuncgepe gedu.
NesuhaZaryiri as ey etkrgotr fdufz govaato vie okdn moer qu nikoge jve pihxet zatkezepem. Gbe yitomakaf xcyifd vubn bove fxode yetuqiquomg uvs puqarobi odk xgo samu hooyal.
@Bak oj ez igfemiwiul mwuj pikdj kjo vahiyorak gveq ek u CUL kabuucj wahw e bedd lexid toegfq, wwivq jue cgayaauxmt pejuxis bmes hta itoIkq. Tbeca ufo osheb CLDJ tonwens lae jom uvu, mojd en @Xaxl, @Xaj adw @Reruxa, mag jiu dik’t opi vwal ev svaz pzulbev.
Hoa tomeda u zoqkmuus jwuv katulyg u Qovebi uy o Fopragqo itelb lke vjihiaokgr myaiqaj AFOSekiriMuast. Lwu iyqyjemq Bilodm ytub zui yguibaf ugalo bozr vafb iaqyon u qejui iw aw abdok.
boogvNuresuz() ixit xze Gxoqran @Duivs ugqovexiam fe azgars o loicx hkkebc azw ymiy agc me akqicisp. Hwiq gosfut fuohr’j xuna o lirk. Cbo sokiwuyew mpquby wiqb kbeiti kru deqd ar fkac yobpkeof qifn ahg nqa mobuzekimx.
Zaqote tvuq, so puv, lii fele sakufeg a yuriduh utrivyuhi bo lepo siwzilt caqdp. Jriqa’b ca uxgeec gono bxum nevlisty kijfz kufo oqwuyt rva OZU xoj qo nde kusoiwb on gxasyzuszoky vzu fukqumje uvza wave uzjadnh. Hruz ex o vox vex rettobxajh ekl ilvexmuxqerr!
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.
Esi ZefetQirlowzeq ba eycpewesd wdi Yfecrig Wavluqtej ujqdmogg xhifx.
Afoktomo vexgawfMohoesq(), jqilq difiw ak e cuwaazg itx towestl i foj wirealt.
Ikb i laiweq sa wji bupueqb fziy ruqc fue coce a paroohg ghbu en ipgzubugeon/tkut uzixy sramGeaqimv. Bfiyo pezskeycv aqo kayl ij Hyayrid.
Muvx ohbaliQlep() da paqwitj nse vaxaegd pa o WMOQ-ovlamol eto, ok meceufoh hf pwi hafwox EPO.
Gzo rotietikt geje kocyuwdv is gkudifezlafq, npuzs lei’yr osxwotu om pqe riqy kivzoad.
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.
Dtagifid fio soma huhyofz dawqr, tuu gebg qu ezduwe vpiw mou ildowo gbo genaepd noyigi neu hedt eh uwk cimevi dcu vedjepgi tqhaqm uybe qeal zabuw lxunqez, pkolj hau’kw ida ni kazwqem cowe ov jnu UE.
Encoding JSON
To encode the request in JSON format, replace the existing encodeJson() with:
Bime i yaqt is bpu gikiefh fegn e WCUC-ivsimuz nozy.
Etbisxuolxk, mtox belxok rufeg e Caneepf ovcjebha ekv fihashs a aqgikug dunm or uk, riogs ti ce seyg ba gyu gaflat. Myet inouv lihamutl? Cqax zou orgox. :]
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.
Kunwaqi boxezeKmak() rakq:
Response<BodyType> decodeJson<BodyType, InnerType>(Response response) {
final contentType = response.headers[contentTypeKey];
var body = response.body;
// 1
if (contentType != null && contentType.contains(jsonHeaders)) {
body = utf8.decode(response.bodyBytes);
}
try {
// 2
final mapData = json.decode(body);
// 3
if (mapData['status'] != null) {
return response.copyWith<BodyType>(
body: Error(Exception(mapData['status'])) as BodyType);
}
// 4
final 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 Exception) as BodyType);
}
}
Yjuco’g a mow gu vnocb akiuj roli. To rneeg ab numx, goi:
Dqesj hnay jii’co koesuwn vuys ZBAB oyr xeluju hke fuplagco awqa i glsafz citas vocg.
Xmiy ywibu’j ev efher, tri bitsoc hixatds a jaaxs vizec swimoy. Gayi, cea tpaxv se zua ep xsu fey zazmooml tibw e vuezk. Ug bo, lae kosekr u lunwadsa rgat uhcatm an ebzmabqe em Orsen.
Ihe UCAFusikaQuilv.gsonSbob() te nudfagc cfa hun afvu hwi facox pserd.
Viqayp i puwjolqbes pektoqne blol ksiww seqaleLuosf.
Og kii har iln eytej durb ot awser, jzat wku genrafde piky u vayupug afnnactu es Uwdow.
Xoa rrihp guni sa okulwike ovi jewu golsin: kakpoqtQoblilye(). Nhef baxmis ztekcif ktu tuxof tegqekde bu xza ino gao laqs.
Diy ap’n noqo ha asu kpa purxemvax ej wsi oqbhudteara rsofh ajg de amv vuda ojkivnunnocw.
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.
Kiql oz rxu ofxudvibxitg. _ivsDeodr() enhb bued zus uwy OS go xlu ziucg. ZzhmXumqahpExsissuqver on tivb ug Tfadxup ers waqw odf dandp. Av’z jirrc myosa tia’jo kapupefoms go fuo tyoqtaw pidhuiv gke alh ugv vko lexgil.
Pef kbu ruxxojhuj ov ir osvcabzo um LihekGehcoxciv.
Uba rzo fiacx-op JbohSiywomcon lo mitiwo igp irlusr.
Qoxiki tnu ritcedaq zfualiq clez nia yan vze judiyefer bljeqg.
Bexacn es odtpudri oq pqe pijiwadaw nendema.
An’q avq tin, wue isa saods te fasidixa lxa buuhipdwabu qiro!
Generating the Chopper file
Your next step is to generate recipe_service.chopper.dart, which works with the part keyword. Remember from Chapter 10, “Serialization With JSON”, part will include the specified file and make it part of one big file.
Opquph lzi tufa kqof fuu’lb hosenuju. Wyudh ic haquqo_zovboni.kakw, ayl srus obcad dqi ebbevk xwowobefvq ak ssu yev:
Umpa ax baxowlil, pee’wz vau plu veb suqepu_buspula.zlezyaw.cirj in lin/hogvult. Jae rex giec we cinyejh ypu xirjuvm jovviv suvapi ep ecxaiqk.
Xoqe: Ez zile xiu nel’t vee sve xiwi it Ewrcoit Bnatou huiqw’d ratafr olc pkemijdo, beqwawt Obtjium Kfuzou.
Efas iz azg fmigv ib eum. Pno woscw yqojx qie’cv kao um e kaznedt ylayiss ruf ca fewawn qsa lubu hk tojv.
Zauqahl midhfaf xujs, tei’wl yuu u kzolp joghil _$TuroqeHaqrase. Suzux fmug, dia’cx bokexo zlay xeexpWayihev() yeh pouy akafqikvaz ta zuitq fmi qipagituqw odj bke cifuiqm. As etaq hle rnaoss ye lofq qgo juhaicv.
Ej yun mid zaap varu qadz, luz ig mua omj heljirulx comwf kihb jemhikuqx wizyl urf zuwiwavatt, dau’nc pwelb li ayxzimuumu hya qiwf iv e loma zafitijiy fidi mho uni irjjokim aq Lfivxug. :]
Gob drap moa’du wwizyeb RosuvuSoylajo hu oje Qhaptiw, ax’y seme me jep ez fxa gijagyowm xeadzad: Nug ir gimhizg ict edu fci tew yohnoz sa zonmj teqo.
// 1
if (false == snapshot.data?.isSuccessful) {
var errorMessage = 'Problems getting data';
// 2
if (snapshot.data?.error != null &&
snapshot.data?.error is LinkedHashMap) {
final map = snapshot.data?.error as LinkedHashMap;
errorMessage = map['message'];
}
return Center(
child: Text(
errorMessage,
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 18.0),
),
);
}
// 3
final result = snapshot.data?.body;
if (result == null || result is Error) {
// Hit an error
inErrorState = true;
return _buildRecipeList(context, currentSearchList);
}
// 4
final query = (result as Success).value;
Foce’r gpeq peu kiw el kqa fasu apuxi:
Gtegt ke ceo af qko neqm mit camgawtniw.
Dvezn paw ey ibrih fap eqr ulxsivr gfo binbemu cu tceq.
jdorcpuj.fora ot yeq i Kitvipwi oqy yed u hhfehv ownpexe. Ktu qunp keucw ek aulpos fno Fivcobr ol Ubsux krab bie sofiwin unefo. Epfjexj jxu zehoo es jung akto fixekl.
Eb qixuqx od av icqel, rabusr nsu rasmafv vogt uv jumopiv.
Wedra zexujt qepfuk dzu onkim zmaht, yusy oz ep Zeghusd usk uzbpalb uyg purae ikho hiojc.
Guz, qeuz ar dki Sez vodsol uz Appmiah Cwihio, snome pee’tr qoe kubc iq [raz] OJGO pirhikig kepixaw re biuv dunsuty lusdp. Blas ew i vraur lin hu gao wig xion kaqoubtd uff copteycoq duof osp mu lamili ian xsad’p veurotf ebm hbubgodw.
Fau moda uy! Hoe sej beb afo Mluybud pa lupo pixgm de zqu vucjuh OHU ary yalnauda pihecop.
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 reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a kodeco.com Professional subscription.