Services

Services are classes that gets delegated some responsibility by upfront. With services, it's easy to adjust upfront's behaviour without having to extend the model and write elaborate overrides. You may switch them out or extend them to fit your needs. To see how you change the implementations, visit the global config page.

Service Interfaces

Services have some interfaces that they need to implement on order to work.

ApiCaller

ApiCaller an object with a call method defined which is utilized by all the ajax requests initiated by upfront, and it is responsible for sending a request with the given data returning a Promise<ApiResponse>. The arguments the call method takes in order are:

  • url - a string
  • method - a string representing the http method
  • data(optional) - an object or FormDataopen in new window
  • customHeaders(optional) - an object with string keys and string or array of strings value
  • queryParameters(optional) - an object to send as query parameters in the url

HandlesApiResponse

HandlesApiResponse's task is to handle the parsing of the ApiResponse returned by ApiCaller and deal with any errors. It defines a handle method which takes a Promise<ApiResponse> and it should return a Promise<any>.

ApiResponse

As you might have noticed in the above service interfaces they work with an object called ApiResponse as opposed to a Responseopen in new window. This is because this interface is more generic and can easily be implemented if deciding to use something other than the fetchopen in new window api. The only keys always available on the object are the following properties:

TIP

Typescript users may use module augmentationopen in new window to specify what their ApiResponse is actually look like:

// shims/upfront.d.ts
import type { ApiResponse as BaseApiResponse } from '@upfrontjs/framework';

declare module '@upfrontjs/framework' {
    interface ApiResponse extends BaseApiResponse {
        myKey?: string;
    }
}

Upfront provides the implementations for the above interfaces which should cover most use cases. If you don't set your own implementation, upfront will fall back to these default services.

Using Custom Services

Implementing interfaces

If you're thinking about creating your own service, for reference you may check out the interfaces and/or the default implementation's source code.

Creating a service is easy as:

// MyHandler.js
import notification from 'notification-lib';

export default class MyHandler {
    handle(promise) {
        return promise.then(response => {
            if (response.status >= 300 && response.status < 400) {
                // etc...
            }
            // response handling
        })
        .catch(error => notification(error.message));
    }
}

// entry-file.js
import { GlobalConfig } from '@upfrontjs/framework';
import MyHandler from './Services/MyHandler';

new GlobalConfig({
    apiResponseHandler: MyHandler,
})
// MyHandler.ts
import type { HandlesApiResponse } from '@upfrontjs/framework';
import notification from 'notification-lib';

export default class MyHandler implements HandlesApiResponse {
    public handle(promise: Promise<Response>): Promise<any> {
        return promise
            .then(response => {
                if (response.status >= 300 && response.status <= 400) {
                    // etc...
                }
                // response handling
            })
            .catch((error) => notification(error.message))
    }
}

// entry-file.ts
import { GlobalConfig } from '@upfrontjs/framework';
import MyHandler from './Services/MyHandler';

new GlobalConfig({
    apiResponseHandler: MyHandler,
})

Extending Services

If you just want to extend a service to add some functionality like adding initRequest() to the API, that can be achieved like so:

// MyHandler.js
import { ApiResponseHandler } from '@upfrontjs/framework';

export default class MyHandler extends ApiResponseHandler {
    handleFinally() {
        // any operations after the request
    }
}

// entry file.js
import { GlobalConfig } from '@upfrontjs/framework';
import MyHandler from './Services/MyHandler';

new GlobalConfig({
    apiResponseHandler: MyHandler,
})
// MyHandler.ts
import { ApiResponseHandler } from '@upfrontjs/framework';

export default class MyHandler extends ApiResponseHandler {
    public handleFinally(): void {
        // any operations after the request
    }
}

// entry file.ts
import { GlobalConfig } from '@upfrontjs/framework';
import MyHandler from './Services/MyHandler';

new GlobalConfig({
    apiResponseHandler: MyHandler,
})

You can find examples of testing custom services in the Testing section.