api_dynamic365_library 3.0.0 copy "api_dynamic365_library: ^3.0.0" to clipboard
api_dynamic365_library: ^3.0.0 copied to clipboard

A Dart and Flutter helper library for Microsoft Dynamics 365 Finance and Operations OData APIs.

Dynamic365 API Client for Dart & Flutter #

Pub Version GitHub Stars

A Dart and Flutter helper package for integrating with Microsoft Dynamics 365 Finance and Operations OData APIs.

Version 3.0.0 introduces a cleaner OData client, token provider abstraction, paging support, composite key support, structured error handling, and better support for D365FO /data entities.

This package is designed mainly for Dynamics 365 Finance and Operations OData endpoints. For production Flutter mobile apps, avoid storing clientSecret directly inside the app. Use a secure backend or Azure Function to issue tokens or proxy D365FO requests.


Features #

  • Dynamics 365 Finance and Operations OData support through /data endpoints.

  • OAuth 2.0 client credentials token provider.

  • Static token provider for backend-generated access tokens.

  • Token caching with expiry handling.

  • Get entity sets.

  • Get entity by key.

  • Create entity records.

  • Update entity records.

  • Delete entity records.

  • Composite OData key support.

  • OData query builder support:

    • $select
    • $filter
    • $top
    • $skip
    • $orderby
    • $count
    • cross-company
    • dataAreaId company filtering
  • OData paging support using @odata.nextLink.

  • getAllPages helper method.

  • Structured response wrapper with status code, raw body, and next link.

  • Structured exception handling using D365Exception.

  • Flutter and Dart ready.


Installation #

Add the package to your pubspec.yaml:

dependencies:
  api_dynamic365_library: ^3.0.0

Then run:

flutter pub get

or for pure Dart projects:

dart pub get

Import #

import 'package:api_dynamic365_library/api_dynamic365_library.dart';

Quick Start #

1. Create a token provider #

For internal tools or server-to-server scenarios:


final tokenProvider = ClientCredentialsTokenProvider(
  tenantId: 'YOUR_TENANT_ID',
  clientId: 'YOUR_CLIENT_ID',
  clientSecret: 'YOUR_CLIENT_SECRET',
  resource: 'https://your-environment.operations.dynamics.com',
);

Warning: Do not use clientSecret directly in public Flutter mobile apps. For production mobile apps, use a backend API or Azure Function.


2. Create the D365 OData client #


final client = D365ODataClient(
  baseUrl: 'https://your-environment.operations.dynamics.com',
  tokenProvider: tokenProvider,
);

Read Entity Data #

Example: Read customers from CustomersV3.


final response = await
client.getEntitySet
(
entityName: 'CustomersV3',
query: D365ODataQuery()
    .company('usmf')
    .select([
'CustomerAccount',
'OrganizationName',
'dataAreaId',
])
    .top(10),
);

for (final row in response.data) {
print(row);
}

Read Entity By Key #


final response = await
client.getEntityByKey
(
entityName: 'CustomersV3',
key: const D365ODataKey({
'dataAreaId': 'usmf',
'CustomerAccount': 'US-001',
}),
);

print(response.data);

Create Entity Record #


final response = await
client.createEntity
(
entityName: 'CustomersV3',
payload: {
'dataAreaId': 'usmf',
'CustomerAccount': 'US-999',
'OrganizationName': 'Test Customer',
'CustomerGroupId': '10',
'CurrencyCode': 'USD',
},
);

print(response.data);

Update Entity Record #

await
client.updateEntity
(
entityName: 'CustomersV3',
key: const D365ODataKey({
'dataAreaId': 'usmf',
'CustomerAccount': 'US-999',
}),
payload: {
'OrganizationName': 'Updated Customer Name',
},
);

Delete Entity Record #

await
client.deleteEntity
(
entityName: 'CustomersV3',
key: const D365ODataKey({
'dataAreaId': 'usmf',
'CustomerAccount': 'US-999',
})
,
);

OData Query Examples #

Select fields #


final query = D365ODataQuery().select([
  'CustomerAccount',
  'OrganizationName',
]);

Filter records #


final query = D365ODataQuery().filter(
  "CustomerGroupId eq '10'",
);

Filter by company #


final query = D365ODataQuery().company('usmf');

This adds:

dataAreaId eq 'usmf'

to the OData filter.

Cross company #


final query = D365ODataQuery().crossCompany();

Top and skip #


final query = D365ODataQuery()
    .top(50)
    .skip(100);

Order by #


final query = D365ODataQuery().orderBy([
  'CustomerAccount asc',
]);

Count #


final query = D365ODataQuery().count();

Paging #

D365FO OData may return @odata.nextLink for large result sets.

Manual paging #


final firstPage = await
client.getEntitySet
(
entityName: 'CustomersV3',
query: D365ODataQuery().top(100),
);

if (firstPage.nextLink != null) {
final secondPage = await client.getNextLink(
nextLink: firstPage.nextLink!,
);

print(secondPage.data);
}

Get all pages #


final rows = await
client.getAllPages
(
entityName: 'CustomersV3',
query: D365ODataQuery().top(100),
maxPages: 20,
);

print
(
rows
.
length
);

Composite OData Keys #

Many D365FO entities use composite keys.


const key = D365ODataKey({
  'dataAreaId': 'usmf',
  'ItemNumber': '1000',
});

The generated OData key will be:

dataAreaId='usmf',ItemNumber='1000'

Using a Backend Token #

For production Flutter apps, the recommended approach is:

Flutter App
    ↓
Backend API / Azure Function
    ↓
Dynamics 365 Finance and Operations

Your backend should handle the client credentials flow securely and return a short-lived access token to the app.

Example using StaticTokenProvider:


final tokenProvider = StaticTokenProvider(
  accessToken: 'ACCESS_TOKEN_FROM_BACKEND',
  expiresAt: DateTime.now().add(
    const Duration(minutes: 50),
  ),
);

final client = D365ODataClient(
  baseUrl: 'https://your-environment.operations.dynamics.com',
  tokenProvider: tokenProvider,
);

When your backend returns a new token:

tokenProvider.updateToken
(
accessToken: 'NEW_ACCESS_TOKEN',
expiresAt: DateTime.now().add(
const Duration(minutes: 50
)
,
)
,
);

Error Handling #

The package throws D365Exception for token errors, HTTP errors, timeout errors, and invalid responses.

try {
final response = await client.getEntitySet(
entityName: 'CustomersV3',
query: D365ODataQuery().top(10),
);

print(response.data);
} on D365Exception catch (e) {
print('D365 error: ${e.message}');
print('Status code: ${e.statusCode}');
print('Response body: ${e.responseBody}');
} catch (e) {
print('Unexpected error: $e');
}

Main Classes #

Class Description
D365ODataClient Main client for D365FO OData operations.
D365ODataQuery Builds OData query parameters.
D365ODataKey Builds single or composite OData keys.
D365TokenProvider Base abstraction for token providers.
ClientCredentialsTokenProvider Gets OAuth token using client credentials.
StaticTokenProvider Uses an access token provided by another source.
D365Response<T> Wraps response data, status code, raw body, and next link.
D365Exception Structured exception for D365 errors.

Security Notes #

Do not store Azure AD clientSecret inside a public Flutter mobile or web app.

Recommended production architecture:

Flutter App
    ↓
Your Backend API
    ↓
D365FO OData / Custom Service

Use direct ClientCredentialsTokenProvider only for:

  • Internal apps.
  • Admin tools.
  • Local testing.
  • Backend/server-side Dart apps.

Supported D365FO Endpoint Style #

This package expects D365FO OData URLs like:

https://your-environment.operations.dynamics.com/data/CustomersV3

It is not intended for Dataverse CRM Web API URLs like:

https://your-org.crm.dynamics.com/api/data/v9.2/accounts

License #

This project is licensed under the MIT License.

See the LICENSE file for details.

0
likes
140
points
34
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A Dart and Flutter helper library for Microsoft Dynamics 365 Finance and Operations OData APIs.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

http

More

Packages that depend on api_dynamic365_library