Table of Contents


Overview

Appstrax in partnership with CodeCapsules provides software tools and infrastructure to assist in the development, hosting and managing of your applications.

Getting Started

To use the available services, an instance of the Auth, Database and Storage API need to be configured internally.
Each instance deploys a front-end to interact with registered users, application data and uploaded Files accordingly.

To get this instance set-up, first send an email to info@appstrax.tech and we'll help create, host and manage your Appstrax API here: https://codecapsules.io/

Installation

Add appstrax_services as a project dependency:

pub get appstrax_services

Setup

Initialize the appstrax_services libraries:

// import the services library
import 'package:appstrax_services/initialize.dart';

// initialize the service
await initializeAppstraxServices(
  apiUrl: 'https://<your-appstrax-services-instance>',
  apiKey: '<your-appstrax-services-instance-api-key>',
);

Auth Service

This library integrates with the Appstrax Auth API which allows you to easily interact with authentication in your mobile applications.

To get started import appstraxAuth into your project:

import 'package:appstrax_services/auth.dart';

Registration

RegisterDto registerDto = RegisterDto(
  email: 'joe@soap.com',
  password: '<password>',
  data: {
    // any additional/custom user fields
    'name': 'Joe',
    'surname': 'Soap',
    ...
  }
);

try {
  AuthResult result = await appstraxAuth.register(registerDto);
  User user = result.user!;
  print('User Successfully Registered, userId: ${user.id}');
} catch (err) {
  // something went wrong while registering the user
  handleError(err);
}

Login

LoginDto loginDto = LoginDto(
  email: 'email',
  password: '<password>',
);

try {
  AuthResult result = await appstraxAuth.login(loginDto);
  User user = result.user!;
  print('User Successfully Logged In, userId: ${user.id}');
} catch (err) {
  // something went wrong while logging in
  handleError(err);
}

Forgot Password

ForgotPasswordDto forgotPasswordDto = ForgotPasswordDto(
  email: 'email'
);

try {
  Message message = await appstraxAuth.forgotPassword(forgotPasswordDto);
  print('forgotPassword email sent:  ${message.message}');
} catch (err) {
  // something went wrong sending the email
  handleError(err);
}

An email will be sent to the user with a password reset code, this code is only valid for 24 hours.

Reset Password

ResetPasswordDto resetPasswordDto = ResetPasswordDto(
  email: 'email',
  code: '<code>',
  password: '<password>',
);

try {
  Message message = await appstraxAuth.resetPassword(resetPasswordDto);
  print('Password Successfully Reset:  ${message.message}');
} catch (err) {
  // something went wrong while resetting the password
  handleError(err);
}

The password is now reset, however the user will now need to login with their new password.

Change Password

ChangePasswordDto changePasswordDto = ChangePasswordDto(
  password: '<currentPassword>',
  newPassword: '<newPassword>',
);

try {
  User user = await appstraxAuth.changePassword(changePasswordDto);
  print('Changed password for userId: ${user.id}');
} catch (err) {
  // something went wrong while changing the password
  handleError(err);
}

Users can only change their password if they are already authenticated.

Save User Data/Profile

try {
  User updatedUser = await appstraxAuth.saveUserData({
    // any additional/custom user fields
    'name': 'Joe',
    'surname': 'Soap',
    'career': 'Software Engineer',
    ...
  });
  print('user data successfully updated, userId: ${updatedUser.id}');
} catch (err) {
  // something went wrong while updating the user data
  handleError(err);
}

Users can only update their data if they are already authenticated.

Logout

try {
  await appstraxAuth.logout():
} catch (err) {
  // something went wrong while logging out
  handleError(err);
}

Auth Error Messages

class AuthErrors {
  // registration errors
  static const emailAddressAlreadyExists = 'emailAddressAlreadyExists';
  static const badlyFormattedEmailAddress = 'badlyFormattedEmailAddress';
  static const noPasswordSupplied = 'noPasswordSupplied';

  // login errors
  static const invalidEmailOrPassword = 'invalidEmailOrPassword';
  static const userBlocked = 'userBlocked';
  static const invalidTwoFactorAuthCode = 'invalidTwoFactorAuthCode';

  // forgot/reset password errors
  static const emailAddressDoesNotExist = 'emailAddressDoesNotExist';
  static const invalidResetCode = 'invalidResetCode';

  // unknown errors
  static const unexpectedError = 'unexpectedError';
}

User Service

This library integrates with the Appstrax Auth API which allows you to easily manage the users in your mobile applications.

To get started import appstraxUsers into your project:

import 'package:appstrax_services/auth.dart';

Public Availability

Admin Panel -> Configuration tab -> Public Access -> toggle 'Allow Public Access'

Querying Users

The appstraxUsers.find() function takes a FetchQuery as an argument and returns a FindResultDto

Examples

A query to search for the users table similar to:

SELECT * FROM users WHERE email LIKE '%Joe%' ORDER BY email ASC LIMIT 5
FetchQuery query = FetchQuery(
  // where: {"email":{"LIKE":"Joe"}}
  where: { email: { Operator.LIKE: 'Joe' } },
  // order: {"email": "ASC"}
  order: {},
  offset: 0,
  limit: 5,
);

try {
  FindResult users = await appstraxUsers.find(query: query);
  totalUsers = users.count;
  userData = users.data;
} catch (err) {
  // something went wrong while querying the users
  handleError(err);
}

A query to search for the users table similar to:

SELECT * FROM users WHERE email LIKE '%Joe%' OR name LIKE '%Joe%' OR surname LIKE '%Joe%' LIMIT 5
FetchQuery query = FetchQuery(
  // where: {"OR":[{"email":{"LIKE":"cam"}},{"name":{"LIKE":"cam"}},{"surname":{"LIKE":"cam"}}]}
  where: {
    Operator.OR: [
      { email: { Operator.LIKE: 'Joe' } },
      { name: { Operator.LIKE: 'Joe' } },
      { surname: { Operator.LIKE: 'Joe' } },
    ],
  },
  // order: {"email":"ASC"}
  order: {"email": OrderDirection.ASC},
  offset: 0,
  limit: 5,
);

try {
  FindResult users = await appstraxUsers.find(query: query);
  totalUsers = users.count;
  userData = users.data;
} catch (err) {
  // something went wrong while querying the users
  handleError(err);
}

try {
  User user = await appstraxUsers.findById(id);
} catch (err) {
  // something went wrong while querying the users
  handleError(err);
}

try {
  User user = await appstraxUsers.findByEmail(email);
} catch (err) {
  // something went wrong while querying the users
  handleError(err);
}

Database Service

This library integrates with the Appstrax Database API which allows you to easily interact with your database in your mobile applications.

To get started import appstraxDb into your project:

import 'package:appstrax_services/database.dart';

Create

// Create a new Document, returns a DocumentDto from the 'testing' collection
try {
  var document = await appstraxDb.create('testing', {
    'name': 'John',
    'surname': 'Doe',
    'dogs': 3,
    'career': 'Software Engineer',
  });
  createdId = document.id;
  print('Document created docId: $createdId');
} catch (err) {
  // something went wrong while creating
  handleError(err);
}

Edit

// edit documents 
try {
  var document = await appstraxDb.edit('testing', createdId, {
    'name': 'John',
    'surname': 'Doe',
    'dogs': 3,
    'career': 'Senior Software Engineer',
    'added': 'this field'
  });
  print('Document edited: ${document.id}');
} catch (err) {
  // something went wrong while editing
  handleError(err);
}

Delete

// delete documents
 try {
  await appstraxDb.delete('testing', createdId as String);
  print('Document deleted.');
} catch (err) {
  // something went wrong while deleting
  handleError(err);
}

Find By Id

// findById returns a DocumentDto from the 'testing' collection
try {
  var document = await appstraxDb.findById('testing', createdId as String);
  print('Document foundById: ${document.id}');
} catch (err) {
  // something went wrong while querying the 'testing' collection
  handleError(err);
}

Find

// find returns a FindResultDto<DocumentDto>
try {
  var documents = await appstraxDb.find('testing');
  if (documents.data?.length != null) {
    documents.data?.forEach((user) {
      print('docId: ${user.id}');
    });
  }
} catch (err) {
  // something went wrong while querying the 'testing' collection
  handleError(err);
}

// find accepts a FetchQuery as in examples above
// You can create compound queries
// Here we search for documents where name=='John' AND dogs IN [1, 5, 7, 2]
try {
  FindResultDto<DocumentDto> documents = await appstraxDb.find(
    'testing',
    query: FetchQuery(
    where: {
      Operator.and: [
        {
          'name': {Operator.equal: 'John'}
        },
        {
          'dogs': {
            Operator.qIn: [1, 5, 7, 2]
          }
        },
      ]
    },
    order: {"email": OrderDirection.ASC},
    offset: 0,
    limit: 5,
    ),
  );
  if (documents.data?.length != null) {
    documents.data?.forEach((user) {
      print('docId: ${user.id}');
    });
  }
  print('Documents found using find(query)');
} catch (err) {
  // something went wrong while querying the 'testing' collection
  handleError(err);
}

CRUD Service

The CrudService is a abstract class which wraps the Create, Read, Update and Delete functions in appstraxDb. The CrudService is declared with a model which extends the Model class, this model is the type that the service Creates, Reads, Updates and Deletes.

Similarly to appstraxDb, the CrudService uses a collection name which represents the "table" that the data is stored in on the server.

To get started import CrudService & Model into your project:

import 'package:appstrax_services/database.dart';

Create your custom Model & Service:

// Create a custom Model that implements the base Model
import 'package:json_annotation/json_annotation.dart';
import 'package:appstrax_services/shared/models/model.dart';

part 'person.g.dart';

@JsonSerializable()
class Person implements Model {
  @override
  String? id;
  @override
  DateTime? createdAt;
  @override
  DateTime? updatedAt;
  String name;
  String surname;
  String career;
  int dogs;

  Person({
    this.id,
    this.createdAt,
    this.updatedAt,
    required this.name,
    required this.surname,
    required this.career,
    required this.dogs,
  });

  factory Person.fromJson(Map<String, dynamic> json) => _$PersonFromJson(json);
  @override
  Map<String, dynamic> toJson() => _$PersonToJson(this);
}

// Generate your person.g.dart file from the terminal with:
	
flutter pub run build_runner build
// Create a custom service for the Model that extends the CRUD service
class PersonService extends CrudService<Person> {
  PersonService() : super('person', Person.fromJson);
}

var personService = PersonService();

We can now use the ProfileService as follows:

// Now you have access to all the CRUD functions on your personService
try {
  Person person = Person(
    name: 'James',
    surname: 'Doe',
    career: 'farmer',
    dogs: 9,
  );

  // save checks for an ID, if it exists the doc is edited else it is created
  var createdPerson = await personService.save(person);
  personCreatedId = createdPerson.id;
  print('Person created: ${createdPerson.id}');
} catch (err) {
  // something went wrong while saving
  handleError(err);
}

// The CRUD service returns the type created ie: Person
try {
  var foundPerson = await personService.findById(personCreatedId as String);
  print('Person foundById: ${foundPerson.id}');
} catch (err) {
  // something went wrong while querying
  handleError(err);
}

// find
try {
  var foundPersons = await personService.find();
  if (foundPersons != null) {
    for (var per in foundPersons) {
      print('DocId: ${per.id}');
    }
  }
} catch (err) {
  // something went wrong while querying
  handleError(err);
}

// The find() accepts a FetchQuery, same as above
try {
  var foundPersons = await personService.find(
    query: FetchQuery(where: {
      'name': {Operator.equal: 'James'}
    }),
  );
  if (foundPersons != null) {
    for (var per in foundPersons) {
      print('DocId: ${per.id}');
    }
  }
} catch (err) {
  // something went wrong while querying
  handleError(err);
}

Storage Service

This library integrates with the Appstrax Storage API which allows you to easily interact with storage in your mobile applications.

To get started import appstraxStorage into your project:

import 'package:appstrax_services/storage.dart';

Examples

// Upload File
try {
  Response res = await appstraxStorage.uploadFile(file, '<folder>/',
    options: HttpOptions(
      onUploadProgress: (progress) => print(
        'Upload Progress: ${progress.percent}',
      ),
  ));
  downloadUrl = res.downloadUrl;
  print('DownloadUrl: ${res.downloadUrl}');
} catch (err) {
  // something went wrong while uploading
  handleError(err);
}

// Delete File using downloadUrl
try {
  await appstraxStorage.deleteFile(downloadUrl as String);
  print('Deleted successfully');
} catch (err) {
  // something went wrong while deleting
  handleError(err);
}

Query Models

The find() function accepts FetchQuery as an argument:

Fetch Query

class FetchQuery {
  // Conditions to query data
  Map<String, dynamic>? where;
  // ASC, DESC Order
  Map<String, dynamic>? order;
  // Pagination variables
  int? offset;
  int? limit;
}

class OrderDirection {
  // Ascending Order Direction
  static const asc = 'ASC';
  // Descending Order Direction
  static const desc = 'DESC';
}

Query Operators

class Operator {
  // Equal To Operator
  static const String equal = 'EQUAL';
  // Not Equal To Operator
  static const String notEqual = 'EQUAL';
  // And Operator
  static const String and = 'AND';
  // Or Operator
  static const String or = 'OR';
  // Greater Than Operator
  static const String gt = 'GT';
  // Greater Than or Equal To Operator
  static const String gte = 'GTE';
  // Less Than Operator
  static const String lt = 'LT';
  // Less Than or Equal To Operator
  static const String lte = 'LTE';
  // Like Operator
  static const String like = 'LIKE';
  // Not Like Operator
  static const String notLike = 'NOT_LIKE';
  // In Operator
  static const String qIn = 'IN';
}

Query Results

The find() function returns a FindResultDto:

// querying the data returns a FindResultDto<DocumentDto> from the collection
class FindResultDto<T extends DocumentDto> {
  List<DocumentDto>? data;
  dynamic where;
  dynamic order;
  int? limit;
  int? offset;
  int? count;

  FindResultDto({
    this.data,
    this.where,
    this.order,
    this.limit,
    this.offset,
    this.count,
  });
}

class DocumentDto {
  final String id;
  final Map<String, dynamic> data;
  final DateTime createdAt;
  final DateTime updatedAt;

  DocumentDto(
    this.id,
    this.data,
    this.createdAt,
    this.updatedAt,
  );
}