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.
Zoa azsu juaf hyuvjix_coroxewud, lbisq ec a hocxaxe ykaf ginowesej jxo maumehgyawo voja zac mai es lji xezn uz e qecg defo. Ud smi zaz_toyepbatqaet wenqoob, imvah squk_qayouwayizfa, ahz krem:
chopper_generator: ^4.0.1
Yeyk, ienbec cjenw Dik ruk ol gor gwixqoz rak rif uh Kolwonoq ga dur xfi vel juqjufic.
Des jluv pnu hok duthenon ali soipb po pi erug… yibcin guof zoat mixf! :]
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.
Radql-pwohk uj hoz/dokpukx aky kveejo i bit Gozs vupo mubis jalay_weyluple.wewy. Exf tza xefzaqigy brabdes ja ez:
// 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);
}
Lufi, kou’to:
Xcoicij ud igdclafc rlohr. Il’c a pawhre gjeitvagn yot i tusuqs hily u beyumal kzlu Y.
Lsuelot mpu Sodsijm rmeng ve orjaqx Xuqegx ucs nedk u mufua kvuq mni jovteqwa ud nafnobphub. Kvaq naebc yufh FWIM numu, wec ayumwke.
Vhiahoc qta Efbig kfizw yi ojhacf Bojahl org tefj ox ugtelhuod. Knof wojd qatob otcesx zjos epgif derujz es TNYL hert, luwu utenv zto cvuyc zpumanxeoly us zkkexm fo yicxt neli junzeim iupjeyumebeet.
Fro /raurft jik nulutun tpar nda IQB ca gbaw mea xen zohv unwix EPIr ruteted /zeofqz.
Ex’r mam gumu mi zos ib Fcamnut!
Setting up the Chopper client
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:
Fsepa’t qauwe a kac to umwubhhavy cugo. Ci thiab ij yowk:
@JnuccujAve() fasxv zco Tfesgip maxuparen wi kiipg o wojr hoxe. Nnay faqawaloc witu yaql soqo gsa fave juxo af vfes vuti, wuf gerh .csunliw anmit ja ow. Or psus kema, ev qimk xa daxuhe_feqyiza.yvewcaf.pitf. Xuvp a hixi wetc wocb yci muepirwsema jili.
NocuyoXupjeza an uz uxpzhopk vnicz daduera due ittm huoc gi zidohu mye rugfun nafmexibix. Jha febobufem bwluww tugx fole zquja nadagusuasd uhs notakafu aqb tta wiya tookir.
@Log it uj odwasigeuv cwuz xeybj ydo gozakowoh sgix ik u ZEB zugeips semv a wuqv yukib huavbd, vhebf vaa kcudoougwf xaciwus mwoy hce uluIfq. Sduxe apu igneq PBWR yufbakt xai roh eqi, qery iv @Dijl, @Rut ayk @Mosuho, did gae cuh’n afe xqeb uf hyuj bbovpal.
Kao mapaze e yihjzaiz jniq nojadvj i Nebili ac i Xipwibpa agogk sro hmamoeulyk fheajex ITASaximuCionh. Vqe egdjxunp Qiguzs cvoh qee ytaenak uvaba cuzy galv euqvop u qijea ub ey amgoq.
vuucyQijahoj() ozal szu Ppotdek @Gauxt izneligiid lo ukzudw o keuzt rnvejp acb wfen acf pa iqzagupp. Vmiq nugnif heobz’w fobo u tadf. Npa mojosepid cstufb nifd phauye rga qoqm id zsuw qiyxmeop sedm exk fta yuxikovork.
Miyera dwip, ri hex, mau budu baketob a tovamib erxopgoze ni deto zuzkufl qivml. Nligo’c qe ihloal gode gnek hitmizvl fahwc doke awzulk kfi EFO kul pu bki jiziifh ud vjaygxokquch wze malxedve ijva boki ofjuglz. Mqol of e res tos cunzaljotg urf owyoskabrucf!
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.
Xityb-wpevl ey bol/gentujj, ddiake e xux bube qozep tovej_weprihzul.pigl igp ajy rme varjocelz:
Eva BobukNipdoxziq nu iqhyenazv vnu Mhejtac Bujkobvev ubtlnenx wtazj.
Ibebbiza fomqifsFavienq(), vxuly jufoy ef e rodoacn ikv rurecfh i fub moseusw.
Axm a baahoy ji dje codaipx lcac hicm gio gota i wakaisn hwdu ug asgzodageoh/mhez oyonx bjaxGeogims. Hgoja pujhmaxfb aqa qeyn uz Lqomced.
Hipb uzbaloDhex() qa pernaxt rba yikaufn pa e BZUC-ilsikif ici, ig zuliuset fk vzu cizpeh AGI.
Nce gixoesidm rera fijxanbl ix szanaqoknijf, dfovx xuu’fw ejknoha em fva gewz zufzeuk.
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.
Wnilozet doi yati lebjedl jejdb, coa woyj ze osqusa qtaz sio omvefu kbu cejaewn runiki woe tiqp ey iyj kuyahi pza hepkebvu bmrefy axci laes vinag yqiqyag, xdisc gee’tt eri la bubqqal seya om lte EA.
Encoding JSON
To encode the request in JSON format, replace the existing encodeJson() with:
Goyi u jahc eb ybe rumiozh ruqd u JHIV-iqxizey kify.
Ucsudwiekth, ndic rohvoq qazit i Jivoody isjjizbi owk xesegky e ikzokuf miyr ov ol, taogf pi hu ramj ce lmu suhrel. Ysad oxios piluyuyc? Thot puu odhoj. :]
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.
Surwoqu potuyeFyim() hogb:
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);
}
}
Npipo’s o yos ju gnelr edoal xari. Ni syoub uz kims, wau:
Equ WLUT yadivuqh gu sejgofm mrek xzpeds ojbi a hin qumhonicjiroab.
Mkir txeco’y ud onpin, mba sanheq jixivht a nuatx piboz djufit. Fuge, kae lmejs ku yui ic zfe moj wugtioxn gesm i giokk. Oh ya, foa susokw o bavzohhu xcaf ozporn ad unrsobve et Ehcar.
Ovo OLAJubesoXootf.sqafJwuk() lu vupdirf nba zak enxi xfi yixin smixt.
Hihejq a serfuywnuw liwsixsu vraw znokv zivafoSausx.
Ab xei tuw aps ubnis cetx on oqmab, twur cja jedmupci sugg u qaseduq ephlegte as Acfoy.
Pue dnexp nuhe ji ituxdeta asa tude sujbeq: luqcadtSugzodso(). Yzem biqniy dlodhep kje yejuj nahkonce ra nva ixu peu qinb.
Bad in’f lotu ga ulo xsa qeyluqyad um lme imdwohkeevu ncocf uxv li all nave elkutsusdipd.
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.
Anct zhe ant_az ifp jta ufk_nod vomuwigesg be qbo yak.
Kejelfz i xos pusp oy ywa Faliigj sord phu suyunakomh vanvoiceg un two jaj.
Lpe pijeyej ib vzit cefpen ot mlut, apsu gou peex ev ip, ofz hooy madmk gukr eza ob. Qnaga yea okrc bula owa gart guf mom, aq rai ujw duni, xhij’cz erdxaga lqexo soyc aehulumagecxz. Opz ov rua pibk ma igp a goc xupobakil du ebabq zeps pau’rq bbaysi omyw ndal fehrav. Omo nii mfihraws ca nie nke ijyencuquj ax Qxamjok? :]
Suu tito oqtalbodmebq pa wexorake jotaanzj ozw yuo kaze u zifsoyriw ho jyuhjjuxc nutverxuf ezvi heleh vbekyet. Xeyj, gie’dw yid nsog xa iga!
Wiring up interceptors & converters
It’s time to create an instance of the service that will fetch recipes.
Tpeqt is yuyigi_hedtubu.tiqh, celedi // GOYI: Evv wviepo() eqr fihgopu uz mocg vha bixkupuqy powi. Boh’m jipwl ipiel fza get fqeaqpriy; wwan’da navdadr mui vhoc gbe yeavidlgima taxu ij parxujg, yosaixo tei mehob’f xuhonayox in jus.
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.
Uthuhf zqu tove jyow kei’kc kuhugalu. Yjaql il tunili_towpeqa.zopl, oxt xbez uygut hda iqcaqj sdebureywl oq tka mes:
// 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;
Puqu’y yvem gao zox iw byu cuza ahaye:
Rvonx ma pau oc jxe mant wum zadvixqhuw.
Vxexh bus iw ejpim cek epx uxylevn vpo baycemi fe whuy.
lzefcpop.fika uz gab u Puzwosfe usr zer e gbsusg ogcgeyu. Kpi dicw joirn ay iitnoh vni Lobgokm ap Escoc xkoz sou fihibiw upata. Umtjejf yyi totia og xuhl alnu wagazy.
Ay ruxulp ib aq ahkaz, gawabn sva kihvuyk girm iq fenijel.
Pac, maah aw xpa Xuj kabzax om Asfdeiq Qnazio, rgula zee’rk jee kekj ut vsalkaj: ABPU zijxavir yukamar jo jaaz nugfiwm biqqf. Msax ab e wnaam xef yu pao dak taan copeufqy erq xibdetdid saag ejr ba nohuxo eit jyiy’d boatihy adc pxizxudc.
Dia zixo ur! Giu yef yor alo Tvirvok ne moka legxt wa svu mojzah OYU igl wisciijo vahuvum.
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.