Adonis Service Repository
Service repository is a pattern to separate business logic and query logic. This package is designed to help simplify the maintenance of large and medium scale applications.
Installation
node ace add @adityadarma/adonis-service-repository
Usage
*Service
Create service
node ace make:service ServiceName
Using Core or Base
If you want to change the core service according to your wishes without changing the existing methods, you can publish it first.
node ace service:publish
Used on controller
construct(protected serviceName: Service) {}
async data()
{
// Get data
const result = await this.userService.methodName()
return result.getData()
// OR
return (await this.userService.methodName()).getData()
}
async jsonResponse({ response }: HttpContext)
{
const result = await this.userService.methodName()
return result.getApiResponse()
// OR
return response.status(result.getCode()).json(result.getApiResponse())
}
// Set resource on controller
async withResource({ response }: HttpContext)
{
const result = await this.userService.methodName()
return await result.setResource(ResourceName)
// OR
return response.status(result.getCode()).json((await result.setResource(UserResource)).getApiResponse())
// OR
return response.status(result.getCode()).json((await result.setResource(UserResource)).withoutCode().getApiResponse())
}
Use Service & Exception
Every all exception, must have handle to class ServiceException
async methodName()
{
try {
.........
if (false) {
throw new ServiceException('Error exception');
}
..........
return this.setMessage('Message data')
.setCode(200)
.setData(data)
// OR
return this.setMessage('Message data')
.setCode(200)
.setData(data)
.setResource(ClassResource) // if you want set resource in service
.setPaginateCase('snakeCase') // if you want change key pagination case
} catch (error) {
return this.exceptionResponse(error)
}
}
*Repository
Create repository
node ace make:repository nameRepository
Used on service
construct(protected repositoryName: Repository) {}
async methodName()
{
this.repositoryName.functionName();
}
*Resource
Create Resource
node ace make:resource nameResource
Sync or async toObject
toObject() can be sync or async, whichever fits the resource. The static
item() and collection() helpers follow it: an async toObject() gives back a
promise, a sync one gives back the value directly, so you only await when the
resource actually needs it.
// Sync -- no await needed
class RoleResource extends BaseResource<Role> {
toObject() {
return { id: this.resource.id, name: this.resource.name }
}
}
const role = RoleResource.item(model) // { id: 1, name: 'Admin' }
const roles = RoleResource.collection(models) // [{ id: 1, name: 'Admin' }]
// Async -- await, e.g. when loading a relation
class UserResource extends BaseResource<User> {
async toObject() {
return {
id: this.resource.id,
roles: RoleResource.collection(await this.resource.related('roles').query()),
}
}
}
const user = await UserResource.item(model)
Awaiting a sync resource is still valid, so await Resource.item(...) works
either way. setResource() in a service accepts both without any change.
Used on service
async methodName()
{
try {
.........
if (false) {
throw new ServiceException('Error exception');
}
..........
return this.setMessage('Message data')
.setCode(200)
.setData(data)
.setResource(ClassResource)
} catch (error) {
return this.exceptionResponse(error);
}
}
License
This package is open-sourced software licensed under the MIT license.