Introduction

simple_api_call is a super simple dart package to perform api call. Its SDK is much easier to use so that you can focus on business logic. Its build on top of dio package.

Features

  • Supported HTTP methods: GET, POST, PUT, PATCH, DELETE
  • JSON Request Body (sets headers automatically)
  • Form Data Request Body (with easy interface for single/multiple - fields and files)
  • Form URL Encoded Body
  • URL search params (aka URL Query)
  • Request headers
  • Request body
  • Timeout for API Call abort
  • On upload progress update handler
  • On download progress update handler
  • Streams feature for SSE based response

Examples

Example 1: Simple GET api call

import 'package:simple_api_call/simple_api_call.dart';

void main() async {
  var res = await apiCall('https://jsonplaceholder.typicode.com/todos/1');
  print(res);
}

Output:

ApiResponse(
  Ok: true
  Headers: {x-ratelimit-reset: 1739370722, x-ratelimit-limit: 1000, date: Sun, 16 Feb 2025 08:01:31 GMT, transfer-encoding: chunked, vary: Origin, Accept-Encoding, content-encoding: gzip, x-ratelimit-remaining: 999, pragma: no-cache, server: cloudflare, reporting-endpoints: heroku-nel=https://nel.heroku.com/reports?ts=1739370677&sid=e11707d5-02a7-43ef-b45e-2cf4d2036f7d&s=c4034Ntzv9xG2rv4p9jTn01XXS2WI5YBk%2BZUpEh0KUI%3D, cf-ray: 912c029eaf420da6-MRS, etag: W/"53-hfEnumeNh6YirfjyjaujcOPPT+s", connection: keep-alive, cache-control: max-age=43200, age: 5384, server-timing: cfL4;desc="?proto=TCP&rtt=256732&min_rtt=255916&rtt_var=97601&sent=5&recv=6&lost=0&retrans=0&sent_bytes=2809&recv_bytes=719&delivery_rate=14288&cwnd=252&unsent_bytes=0&cid=7168a6c4413b1290&ts=304&x=0", report-to: {"group":"heroku-nel","max_age":3600,"endpoints":[{"url":"https://nel.heroku.com/reports?ts=1739370677&sid=e11707d5-02a7-43ef-b45e-2cf4d2036f7d&s=c4034Ntzv9xG2rv4p9jTn01XXS2WI5YBk%2BZUpEh0KUI%3D"}]}, cf-cache-status: HIT, content-type: application/json; charset=utf-8, access-control-allow-credentials: true, x-powered-by: Express, alt-svc: h3=":443"; ma=86400, nel: {"report_to":"heroku-nel","max_age":3600,"success_fraction":0.005,"failure_fraction":0.05,"response_headers":["Via"]}, via: 1.1 vegur, x-content-type-options: nosniff, expires: -1}
  Status Code: 200
  Status Message: OK
  JSON: {userId: 1, id: 1, title: delectus aut autem, completed: false}
  Body: {userId: 1, id: 1, title: delectus aut autem, completed: false}
)

Example 2: POST api call

import 'package:simple_api_call/simple_api_call.dart';

void main() async {
  var res = await apiCall(
    'https://jsonplaceholder.typicode.com/todos',
    options: Options(
      method: HttpMethod.post,
      json: {'title': 'foo', 'body': 'bar', 'userId': 1},
    ),
  );
  print('res.ok: ${res.ok}');
  print('res.statusCode: ${res.statusCode}');
  print('res.statusMessage: ${res.statusMessage}');
  print('res.json: ${res.json}');
  print('res.body: ${res.body}');
  print('res.headers: ${res.headers}');
  print('res.error: ${res.error}');
}

Output:

res.ok: true
res.statusCode: 201
res.statusMessage: Created
res.json: {title: foo, body: bar, userId: 1, id: 201}
res.body: {title: foo, body: bar, userId: 1, id: 201}
res.headers: {x-ratelimit-reset: 1739693050, x-ratelimit-limit: 1000, date: Sun, 16 Feb 2025 08:03:50 GMT, vary: Origin, X-HTTP-Method-Override, Accept-Encoding, x-ratelimit-remaining: 999, access-control-expose-headers: Location, pragma: no-cache, server: cloudflare, location: https://jsonplaceholder.typicode.com/todos/201, reporting-endpoints: heroku-nel=https://nel.heroku.com/reports?ts=1739693030&sid=e11707d5-02a7-43ef-b45e-2cf4d2036f7d&s=8toGMSh4ryWYsHycTphGd5%2B01FspBh5NXllaidi2q1s%3D, content-length: 65, cf-ray: 912c06004b73b6c4-MRS, etag: W/"41-S72XhYKRBNSGo0mxoArJPNcK+ug", connection: keep-alive, cache-control: no-cache, server-timing: cfL4;desc="?proto=TCP&rtt=259667&min_rtt=254705&rtt_var=79955&sent=5&recv=6&lost=0&retrans=0&sent_bytes=2810&recv_bytes=809&delivery_rate=13078&cwnd=252&unsent_bytes=0&cid=af55f34cf6f28bc5&ts=580&x=0", report-to: {"group":"heroku-nel","max_age":3600,"endpoints":[{"url":"https://nel.heroku.com/reports?ts=1739693030&sid=e11707d5-02a7-43ef-b45e-2cf4d2036f7d&s=8toGMSh4ryWYsHycTphGd5%2B01FspBh5NXllaidi2q1s%3D"}]}, cf-cache-status: DYNAMIC, content-type: application/json; charset=utf-8, access-control-allow-credentials: true, x-powered-by: Express, alt-svc: h3=":443"; ma=86400, nel: {"report_to":"heroku-nel","max_age":3600,"success_fraction":0.005,"failure_fraction":0.05,"response_headers":["Via"]}, via: 1.1 vegur, x-content-type-options: nosniff, expires: -1}
res.error: null

Example 3: Form Data Upload with progress updates

import 'package:simple_api_call/simple_api_call.dart';

void main() async {
  var res = await apiCall(
    'https://api.escuelajs.co/api/v1/files/upload',
    options: Options(
      method: HttpMethod.post,
      formData: FormData(
        fields: {
          'name': 'Rituraj',
          'age': ['20'],
        },
        files: {
          'file': 'pubspec.lock',
          'songs': ['music.mp3', 'tune.mp3'],
        },
      ), // files must exist
      onSendProgress: (sent, total) {
        print('Sent: $sent/$total (${(sent * 100 / total).toStringAsFixed(2)}%)');
      },
      onReceiveProgress: (sent, total) {
        print('Receive: $sent/$total (${(sent * 100 / total).toStringAsFixed(2)}%)');
      },
    ),
  );
  print(res);
}

Output:

Sent: 29/3627 (0.80%)
Sent: 76/3627 (2.10%)
Sent: 83/3627 (2.29%)
Sent: 85/3627 (2.34%)
Sent: 114/3627 (3.14%)
Sent: 160/3627 (4.41%)
Sent: 162/3627 (4.47%)
Sent: 164/3627 (4.52%)
Sent: 193/3627 (5.32%)
Sent: 305/3627 (8.41%)
Sent: 3594/3627 (99.09%)
Sent: 3596/3627 (99.15%)
Sent: 3627/3627 (100.00%)
Receive: 115/115 (100.00%)
ApiResponse(
  Ok: true
  Headers: {connection: keep-alive, x-powered-by: Express, date: Sun, 16 Feb 2025 08:04:57 GMT, access-control-allow-origin: *, reporting-endpoints: heroku-nel=https://nel.heroku.com/reports?ts=1739693097&sid=c46efe9b-d3d2-4a0c-8c76-bfafa16c5add&s=pThExivs6OFFk10FdWiMWDPpdrYPBMn2JwAw2nfMGyY%3D, content-length: 115, nel: {"report_to":"heroku-nel","max_age":3600,"success_fraction":0.005,"failure_fraction":0.05,"response_headers":["Via"]}, report-to: {"group":"heroku-nel","max_age":3600,"endpoints":[{"url":"https://nel.heroku.com/reports?ts=1739693097&sid=c46efe9b-d3d2-4a0c-8c76-bfafa16c5add&s=pThExivs6OFFk10FdWiMWDPpdrYPBMn2JwAw2nfMGyY%3D"}]}, etag: W/"73-SLAWrBZ33uCwI32OGJXhg1FCtdU", via: 1.1 vegur, content-type: application/json; charset=utf-8, server: Cowboy}
  Status Code: 201
  Status Message: Created
  JSON: {originalname: pubspec.lock, filename: b610.lock, location: https://api.escuelajs.co/api/v1/files/b610.lock}
  Body: {originalname: pubspec.lock, filename: b610.lock, location: https://api.escuelajs.co/api/v1/files/b610.lock}
)

Example 4: API call with custom timeout and URL search params (query)

import 'package:simple_api_call/simple_api_call.dart';

void main() async {
  var res = await apiCall(
    'https://jsonplaceholder.typicode.com/todos',
    options: Options(
      timeout: Duration(milliseconds: 100),
      query: {'limit': '20', 'page': '1'},
    ),
  );
  print(res);
}

Output:

ApiResponse(
  Ok: false
  Headers: {}
  Error: The request connection took longer than 0:00:00.100000 and it was aborted. To get rid of this exception, try raising the RequestOptions.connectTimeout above the duration of 0:00:00.100000 or improve the response time of the server.
)

Example 5: Form Url Encoded data api call

import 'package:simple_api_call/simple_api_call.dart';

void main() async {
  var res = await apiCall(
    'https://mocktarget.apigee.net/echo',
    options: Options(
      method: HttpMethod.post,
      formUrlEncoded: {'name': 'Rituraj', 'age': 30},
    ),
  );
  print(res);
}

Output:

ApiResponse(
  Ok: true
  Headers: {x-powered-by: Apigee, alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000, date: Sun, 16 Feb 2025 08:06:38 GMT, access-control-allow-origin: *, content-length: 444, etag: W/"1bc-+bZufFj37PLWVN5Lb9i9Z3e9/lE", via: 1.1 google, x-frame-options: ALLOW-FROM RESOURCE-URL, content-type: application/json; charset=utf-8, x-xss-protection: 1, x-content-type-options: nosniff}
  Status Code: 200
  Status Message: OK
  JSON: {headers: {host: mocktarget.apigee.net, user-agent: Dart/3.7 (dart:io), content-type: application/x-www-form-urlencoded, accept-encoding: gzip, content-length: 19, x-cloud-trace-context: c539756f3f0b14f63c988f6d0b6d2491/16056943780855021050, via: 1.1 google, x-forwarded-for: 223.185.63.47, 35.227.194.212, x-forwarded-proto: https, connection: Keep-Alive}, method: POST, url: /, args: {}, body: name=Rituraj&age=30}
  Body: {headers: {host: mocktarget.apigee.net, user-agent: Dart/3.7 (dart:io), content-type: application/x-www-form-urlencoded, accept-encoding: gzip, content-length: 19, x-cloud-trace-context: c539756f3f0b14f63c988f6d0b6d2491/16056943780855021050, via: 1.1 google, x-forwarded-for: 223.185.63.47, 35.227.194.212, x-forwarded-proto: https, connection: Keep-Alive}, method: POST, url: /, args: {}, body: name=Rituraj&age=30}
)

Example 6: Sending JSON data in POST using body field

import 'dart:convert';

import 'package:simple_api_call/simple_api_call.dart';

void main() async {
  var res = await apiCall(
    'https://jsonplaceholder.typicode.com/todos',
    options: Options(
      method: HttpMethod.post,
      body: jsonEncode({'title': 'foo', 'body': 'bar', 'userId': 1}),
      headers: {'Content-Type': 'application/json'}
    ),
  );
  print('res.ok: ${res.ok}');
  print('res.json: ${res.json}');
}

Output:

res.ok: true
res.json: {title: foo, body: bar, userId: 1, id: 201}

Example 7: Server Sent Events (SSE)

import 'package:simple_api_call/simple_api_call.dart';

void main() async {
  var res = await apiCall(
    'https://sse-fake.andros.dev/events/',
    options: Options(stream: true),
  );
  res.stream!.listen((e) {
    var msg = String.fromCharCodes(e as List<int>);
    print(msg);
  });
}

Output:

:

event: stream-open
data:
2

event: message
data: {"action": "User disconnected", "name": "Terri"}
2

event: message
data: {"action": "New message", "name": "Angelica", "text": "Up into professional six indicate. Example begin live. Shoulder pattern since.\nMission adult standard blood American. Both company occur parent better."}
2

event: message
data: {"action": "User connected", "name": "Stephen"}
...

References

Feedback

If you like this plugin, then please add stars to this github repository. Also if you have any feedback or suggestions to add more features to this packages, don't hesitate to contact me at riturajshakti@gmail.com.

I hope this packages add value to your life 😀

Thankyou

Libraries

simple_api_call
A dart package for performing api calls in a much simpler way. Its able to perform GET/POST/PUT/PATCH/DELETE with Form Data and JSON support builtin. It also supports Server Sent Events.