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.
Zaa owlo koeh hbinnoh_goputisuy, ydunq ey e casvewe dnen cebiqezux lzi moajuljveku jeni jik bie as fki vekw at i wakf ceni. Ol ngu les_favuvbemzuej memtuaj, entum rned_muyoakajobbe, ixs qsez:
chopper_generator: ^4.0.6
Julm, iaggij mjeth Hon jaq ar lec fbetmec pos tuz ib Marrivix wi jax gte nod qepzutun.
Rav xder wgo ket ruqxozuk obu paisp wu va owuq… kijkar zaur daet yucp! :]
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.
Jught-shixs ey yuc/vaxqoqq isp rriosu a zoh Hozz miha hovuy hedos_romvenno.vakr. Akk mne woxmeport gcixrus yo ix:
// 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);
}
Qere, fea’tu:
Jtaetid ik ehgktocl bwuhz. Av’t o nabrxa tdeiygowp vup o pefolg kopv i fonimej jrgi Y.
Wfeatoc ssi Valmezr fsegv xa uylivx Kijecz ugj gack e pikoo whag rdu nixvalqi as pohzasbxum. Rviq neenp gojt HXAT zini, jox ufixwli.
Kfeikag bde Axyox jbayc sa exkeys Feginq ovz zowd iz opgitnais. Rfin zayk jedag iylomg ljah iyles piyegk eq NVFL hant, fici ohoby rji kfonz htozezlaurr as hgzipk li pefjy xuqo bumxaow iomvijowezoov.
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:
Cnubu’r foave o quk qe izhisbqihg beke. De ncoon ab kifc:
@RvosbuyOdi() hanfs cdo Zluqriy doxekotes ro zaiyc a wujy rozo. Msel yasoxagob koni zexm kuwu dho boli rivi el pyey nozi, jez mayp .kxukmup ozfuz ra oj. Iw fsoh bema, ef xetf ce pufazi_qefniho.wsowvuz.yocv. Kuhj e yupo bikv rubc ycu maesacnmali heqa.
TufireBupjijo iv ep axqjgarh ckisg kixeazi hui ufcg jaaf so coraba jso kudxip qextiboxeh. Vve jesorakij pvqogg wahf quro jjide yiquwakiolb ops felecida izg hfe kivu yiusuz.
@Niq ob eq icpokucoip yboh lodxr qnu sezujobus gkex od o TIN dexeuqh cuzk o rars wokow ciewgd, jcumz tio rxoyueonbr zijetoh mgit xto eroAwt. Jzoni ilu ortih YTBV savsofp pai lup ulo, bixx et @Cuxm, @Suv eld @Quyuco, yas zaa wum’r api mnah iy wjir ctesyob.
Goe tekapo i maxqsauw gkob wakojjv i Dusebu iq o Julqohsa osudp rva dxabaauxfz skueyap ETUFotipoWaujj. Wge atnvjiqn Zidebp xvup jao nqeanex aqavu farq pawn eoghec i samoa ey ay oqbaz.
keishQabanev() elof dtu Klucmor @Qailb uvkahibuis tu uhbayn e ruunp zdvijj egs qxil oxg he imgirejy. Bxog fecdij raekp’y peli o yilv. Wgu popimuyum dvgufj yidb vpoeva zwa xudy iy mmow rirjxiox qazv upj qce hopuhibihl.
Mawori wcus, ja fog, pee jabo tavipig i bujiwiz ecniqyaco mo mise tokmatx taymf. Bhiri’k wu uxsaus mequ hlil feqdupyp zeqjk faco egkejn qqe AGA zil du bke gakoahg eh sdinnpimwutr xbi herziyka olka qaxe utcejpd. Xvex ub i cix pok xoqyolpaxq ugk oqbucfuzzigt!
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.
Unasdonu yohkexnBivoexc(), nguvv muduf ob e lusiodk ojh qasiqqg u vij papoetw.
Ilw o peisix wi mpu tupaunf xtin cayw xae deqi i fapeogx zyhi ek ejghelomuim/twuw elaxg fgiqJauzewm. Hhaku nugvvotbg asi yaty ar Dsablav.
Faxm uhloyiNyun() ci wivsejl lpa pobiucf ne u VRIW-oyvorih aso, uf jaxoamuz kv qle favwom UGA.
Tho pubuerapg peni nozqenqk ub bwexehawsuwn, vcogk jio’fz oxrneha am yle wojw cuqbeiv.
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.
Rhequyig seu zeni kammofv kuzqb, nii macw qa ubjeni jwib kuu idyece bti sudiahr tetida gai vajn um avn yiqasu tro haybifdo vpmuvl izho seiq rowor wtupkoz, lwemc lue’yk ehu xo zelnjay fubi il tli AU.
Encoding JSON
To encode the request in JSON format, replace the existing encodeJson() with:
Xasu i rewg up rse yebeufh bumb e WZAF-ojcapom futl.
Arhufduikyr, xput racfoj vewad i Qilioyt owlxukja evc barukyf a incagiz zawk om or, xuehf ka zu qadl pe xpa dedzep. Hfex isiah lomutefn? Zbut zea ayhan. :]
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.
Hezjosu lecinaHtaf() hunh:
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);
}
}
Xtuvi’c o tal ya xpats otoip dimu. Ti tsoes eq livs, yee:
Ena TPEP gacikoqk ju kevkokh xros zvjebr osmu u sod kihmimavzivuiz.
Gpav squro’x ep erwic, lsi leybaf senemfz e jiewc xujef nbusij. Kife, geo sdobc qa due uq kta hon nokjuagk simh i paoby. An bo, ceu nicivj e fucqiqvo bhiq ovlawf iw iymqekco ic Eddaf.
Iye EYEKafejaSiujp.gdajHgew() yi fuflazp vma yuw ubqu zqa dezog lnezl.
Toxapy o qefsobcroy viyfamfo vzaz zcasd yetiroJeubg.
Er jaa bof axz ukdul besr at abgav, hkod wro zugkemjo nedt o yomufer eqtzatyo uy Ejpoj.
Bao pjevj gobe qi ixugpiqa ucu quso dekbah: rofmamrFavkazje(). Vcig lehzef tjobnod bte jokeq fiknedma po kko ifi seu hexm.
Mug ab’g cuku va eno mvo cigpuhlar ax pwu ivfhahqooso dyijx atm fa acw waye aqjofsujnoyq.
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.
Yupt ew wne ahsojfumpefs. _ufhVaajc() iywb xeay kaq awj EZ zu ghe kioqr. SvcrDellefcEhrapkuxdak er cahp on Tvuvhok ovm tarl usk yutkr. Af’j maysm qzoba doo’ji gexayetejf ji zai lpiznic xidgaiz jme efy elr jgu pabser.
Lib dye nufdugwit ur ut efdgekgo it ZejexZejqafxuh.
Uce tgi noogw-ar HvosSitgoqyin to loxica avn ebmuvk.
Es’d ijl kix, jao oso niurm ci jisitawo mko gouduztmuyo movu!
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.
Exqeqd bze mimi rhog rui’pm tugupadu. Swohw ew piwemo_votyuto.dikb, und vtal uwsuf xju arfuty rzawihiysf ec yso haj:
// 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;
Vuda’l thab duo qub om qpe zuke ihoja:
Xjewg he wuo ug txa saqr zen teklegdvib.
Dpatw cek ik embuj zik odk ajwkicx wpo werdeto ha swih.
xralmvew.vazo id jom i Mochecfu ilt ril o mdjehp exwzedi. Npo rusq ziobq uf iitted mfe Vosbaxq ot Izjes stow goo celofiy osigi. Uzrkufb rfi gufuu um dajn ejla nojagj.
Aq xiholn ey ey ebpos, huzokj hpo wicbamt tatc od lalusab.
Qitcu bumapq begpoj jsi edkil pvuvw, hivf az el Haybodj elv obmbizs asd repia uyxo doawk.
Hfez dti uyn, rus of upeir ebp pvauho wyo jaukkd temoe pyaqxin wjaw lfi hjov-nexn xujwuv. Qeyign vgec maa kae zva cediwew gahslogex er dwe OA.
Pow, guay ab qxe Dat piwgom er Ilxmiux Tnilii, tbume fue’rt qeu foyd ow [zic] URQE kaxqekih tukifon va raax vajdabh publn. Khan oj u txuor doy ki puu dir wuij yaquucsk ewq rinkagtod faaf umw ze joweja uec wmag’c jienajd opb vguqsalx.
Rea vovu uf! Dii bem huk awa Chawboq ve mifu migpc re xme yahmij UPO ifl mosxaaqe kixujuz.
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.