{"id":20797697,"url":"https://github.com/beachmachine/ngx-resource-factory","last_synced_at":"2025-05-06T18:43:15.482Z","repository":{"id":28804000,"uuid":"119240957","full_name":"beachmachine/ngx-resource-factory","owner":"beachmachine","description":null,"archived":false,"fork":false,"pushed_at":"2023-01-07T03:58:12.000Z","size":1476,"stargazers_count":11,"open_issues_count":18,"forks_count":3,"subscribers_count":7,"default_branch":"master","last_synced_at":"2024-04-15T01:11:08.892Z","etag":null,"topics":["hacktoberfest"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/beachmachine.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-01-28T08:27:01.000Z","updated_at":"2021-12-25T23:30:57.000Z","dependencies_parsed_at":"2023-01-14T09:37:25.475Z","dependency_job_id":null,"html_url":"https://github.com/beachmachine/ngx-resource-factory","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beachmachine%2Fngx-resource-factory","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beachmachine%2Fngx-resource-factory/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beachmachine%2Fngx-resource-factory/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beachmachine%2Fngx-resource-factory/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/beachmachine","download_url":"https://codeload.github.com/beachmachine/ngx-resource-factory/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252747141,"owners_count":21798091,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hacktoberfest"],"created_at":"2024-11-17T16:34:57.526Z","updated_at":"2025-05-06T18:43:15.463Z","avatar_url":"https://github.com/beachmachine.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ngx-resource-factory\n\nngx-resource-factory is an Angular library that enables you to work with RESTful APIs in an easy way. The main \nfeatures include a resource store for holding changes on resource instances and related resource instances to commit\nthem at once, and an advanced resource caching.\n\n**Note:** This library is for Angular 8.x and above!\n\n\n## In development\n\nThis library is currently in an early stage of development and is missing lots of features as well as a proper \ndocumentation.\n\nYou can find a tutorial on using this library at [this blog entry](https://nezhar.com/blog/consume-rest-api-in-angular-with-ngx-resource-factory/) by [@nezhar](https://github.com/nezhar)\n\n\n## Usage\n\n\n### Install\n\nTo use ngx-resource-factory in your project you have to install it via npm:\n\n    npm i ngx-resource-factory --save\n\n\n### Add resource\n\nThe next step is defining a resource. Typically you create a services folder which will hold a `ServicesModule` in \nwhich the resources will be declared. Resources should also have their own directory. E.g. the `UserResource` would \nbe located in **`app/services/resources/user.resource.ts`**\n\n```typescript\nimport { Injectable } from \"@angular/core\";\n\nimport { environment } from '../../../environments/environment';\n\nimport { Resource } from 'ngx-resource-factory/resource/resource';\nimport { ResourceConfiguration } from 'ngx-resource-factory/resource/resource-configuration';\nimport { ResourceInstance } from 'ngx-resource-factory/resource/resource-instance';\n\n\nexport class User extends ResourceInstance {\n    pk: number;\n    url: string;\n    username: string;\n    email: string;\n}\n\n@Injectable()\n@ResourceConfiguration({\n    name: 'UserResource',\n    url: environment.apiUrl + 'user/:pk/',\n    pkAttr: 'pk',\n    instanceClass: User,\n    stripTrailingSlashes: false,\n})\nexport class UserResource extends Resource\u003cUser\u003e {\n\n}\n```\n\n\n### Create Service module\n\nAfter defining the first resource service it is required to declare it in a module so that we can inject it into \ncomponents. Here, in **`app/services/services.module.ts`**, we are going to define the `ServicesModule`, which will \nload the `UserResource`.\n\n```typescript\nimport { ModuleWithProviders, NgModule } from '@angular/core';\n\nimport { UserResource } from './resources/user.resource';\n\n\n@NgModule({\n    imports: [],\n    exports: [],\n    declarations: [],\n    providers: [/* declare in `forRoot()` */],\n})\nexport class ServicesModule {\n\n    static forRoot(): ModuleWithProviders {\n        return {\n            ngModule: ServicesModule,\n            providers: [\n                UserResource\n            ]\n        }\n    }\n\n}\n```\n\n\n### Add module\n\nFinally we have to add the NgxResourceFactoryModule and the ServicesModule to the main Angular module.\n\n```typescript\nimport { NgxResourceFactoryModule } from 'ngx-resource-factory';\nimport { ServicesModule } from './services/services.module';\n\n\n@NgModule({\ndeclarations: [\n    AppComponent\n],\nimports: [\n    BrowserModule,\n    \n    // ...\n    NgxResourceFactoryModule.forRoot(),\n    ServiceModule.forRoot(),\n    // ...\n],\nproviders: [],\nbootstrap: [AppComponent]\n})\nexport class AppModule { \n\n}\n```\n\n\n## Usage\n\nYou can now inject the resource into your component and start using it.\n\n```typescript\nimport { Component, OnInit } from '@angular/core';\n\nimport { ResourceModel } from 'ngx-resource-factory/resource/resource-model';\n\nimport { UserResource, User } from './services/resources/user.resource';\n\n\n@Component({\n    selector: 'app-root',\n    templateUrl: './app.component.html',\n    styleUrls: ['./app.component.scss']\n})\nexport class AppComponent implements OnInit {\n    title = 'app';\n\n    users: ResourceModel\u003cUser\u003e[] = [];\n\n    constructor(private userResource: UserResource) {\n    }\n\n    ngOnInit() {\n        const queryParam = {};\n\n        this.userResource.query(queryParam).$promise\n            .then((data) =\u003e {\n                this.users = data;\n\n                console.log(data);\n            })\n            .catch((error) =\u003e {\n                console.log(error);\n            });\n    }\n\n}\n```\n\n\n## Action methods\n\nngx-resource-factory exposes the REST APIs methods via its `ActionMethod` methods. The default defines the typical\nRESTful methods on the resource class as follows:\n\n* `.query()` executes `GET` for getting lists\n* `.get()` executes `GET` for getting instances \n* `.save()` executes `POST` for creating instances \n* `.update()` executes `PATCH` for updating instances\n* `.remove()` executes `DELETE` for removing instances\n\nEach of this resource methods can take the parameters, in the given order, as follows:\n\n* `query` optional parameter for URL query data as object\n* `payload` optional parameter for the requests payload as object\n* `successCb` optional parameter for the success callback as function\n* `errorCb` optional parameter for the error callback as function\n\nEach of this resource methods is also available on a resource instance, prefixed with a `$`:\n\n* `.$query()` executes `GET` for getting lists\n* `.$get()` executes `GET` for getting instances \n* `.$save()` executes `POST` for creating instances \n* `.$update()` executes `PATCH` for updating instances\n* `.$remove()` executes `DELETE` for removing instances\n\nThis resource instance methods can take the parameters, in the given order, as follows:\n\n* `query` optional parameter for URL query data as object\n* `successCb` optional parameter for the success callback as function\n* `errorCb` optional parameter for the error callback as function\n\n\n## Define custom action methods\n\nFor a better understanding how to define custom action methods, have a look at the `Resource\u003cT\u003e` type that defines\nthe default methods.\n\n```typescript\nimport { Injectable } from \"@angular/core\";\n\nimport { ResourceBase } from \"ngx-resource-factory/resource/resource\";\nimport { ResourceInstance } from \"ngx-resource-factory/resource/resource-instance\";\nimport { ResourceAction } from \"ngx-resource-factory/resource/resource-action\";\nimport { ResourceActionMethod } from \"ngx-resource-factory/resource/resource-action-method\";\nimport { ResourceActionHttpMethod } from \"ngx-resource-factory/resource/resource-action-http-method\";\n\n\n@Injectable()\nexport abstract class Resource\u003cT extends ResourceInstance\u003e extends ResourceBase {\n\n    @ResourceAction({\n        method: ResourceActionHttpMethod.GET,\n        paramDefaults: [],\n        isList: true,\n    })\n    query: ResourceActionMethod\u003cany, any, T[]\u003e;\n\n    @ResourceAction({\n        method: ResourceActionHttpMethod.GET,\n        isList: false,\n    })\n    get: ResourceActionMethod\u003cany, any, T\u003e;\n\n    @ResourceAction({\n        method: ResourceActionHttpMethod.POST,\n        paramDefaults: [],\n        isList: false,\n        invalidateCache: true,\n    })\n    save: ResourceActionMethod\u003cany, any, T\u003e;\n\n    @ResourceAction({\n        method: ResourceActionHttpMethod.PATCH,\n        isList: false,\n        invalidateCache: true,\n    })\n    update: ResourceActionMethod\u003cany, any, T\u003e;\n\n    @ResourceAction({\n        method: ResourceActionHttpMethod.DELETE,\n        isList: false,\n        invalidateCache: true,\n    })\n    remove: ResourceActionMethod\u003cany, any, T\u003e;\n\n}\n```\n\nYour resource class may inherit from `Resource\u003cT\u003e` or from `ResourceBase`, if you do not want to\nhave the default action methods. Define custom action methods on your resource class as shown above.\n\n```typescript\n@Injectable()\n@ResourceConfiguration({\n    name: 'UserResource',\n    url: environment.apiUrl + 'user/:pk/',\n    pkAttr: 'pk',\n    instanceClass: User,\n    stripTrailingSlashes: false,\n})\nexport class UserResource extends Resource\u003cUser\u003e {\n    @ResourceAction({\n        method: ResourceActionHttpMethod.POST,\n        isList: false,\n        invalidateCache: true,\n        urlSuffix: 'deactive/'\n    })\n    deactivate: ResourceActionMethod\u003cany, any, T\u003e;\n}\n```\n\n\n## Multiple URL params\n\nIt is possible to add multiple params in the URL.\n\n```typescript\n@Injectable()\n@ResourceConfiguration({\n    name: 'UserResource',\n    url: environment.apiUrl + 'user/:pk/',\n    pkAttr: 'pk',\n    instanceClass: User,\n    stripTrailingSlashes: false,\n    paramDefaults: [\n        new ResourceParamDefaultFromPayload('key1', 'key1'),\n        new ResourceParamDefaultFromPayload('key2', 'key2'),\n    ],\n})\nexport class UserResource extends Resource\u003cUser\u003e {\n\n}\n```\n\n```typescript\nconstructor(private userResource: UserResource) {\n    userResource.getOptions().paramDefaults.push(new ResourceParamDefault('key1', 'key1'));\n}\n```\n\nFor custom action methods:\n\n```typescript\n@ResourceAction({\n    method: ResourceActionHttpMethod.POST,\n    paramDefaults: [\n        new ResourceParamDefaultFromPayload('key1', 'key1'),\n        new ResourceParamDefaultFromPayload('key2', 'key2'),\n    ],\n    isList: false,\n});\n```\n\n\n## Handle responses\n\nAction methods give you three ways to handle responses. You can use the stub object returned\nby an action method, that gets filled with data as soon as the response was received, you can use\nthe `.$promise` property to handle the response with a `Promise`, or you can use the `.$observable` \nproperty to handle the response with an `Observable`.\n\nThis may look as follows:\n\n```typescript\nimport { Component, OnInit } from '@angular/core';\n\nimport { ResourceModel } from 'ngx-resource-factory/resource/resource-model';\n\nimport { UserResource, User } from './services/resources/user.resource';\n\n\n@Component({\n    selector: 'app-my',\n    templateUrl: './my.component.html',\n    styleUrls: ['./my.component.scss']\n})\nexport class MyComponent implements OnInit {\n    users: ResourceModel\u003cUser\u003e[] = [];\n\n    constructor(private userResource: UserResource) {\n    }\n\n    ngOnInit() {\n        // Stub\n        this.users = this.userResource.query();\n        \n        // Promise\n        this.userResource.query().$promise\n            .then((data) =\u003e {\n                this.users = data;\n            });\n        \n        // Observable\n        this.userResource.query().$observable\n            .subscribe((data) =\u003e {\n                this.users = data;\n            });\n    }\n\n}\n```\n\n## Notes\n\n#### Usage with Angular 6.x\n\nAngular 6.x is using RxJS 6.x. This has brings some changes in the API of RxJS and requires to additionally install [rxjs-compat](https://www.npmjs.com/package/rxjs-compat). Make sure the version of `rxjs` and `rxjs-compat` are compatible.\n\nThis can be removed and `rxjs-compat` can be moved to peer dependencies once the support for Angular 5.x will be dropped.\n\n#### Internet Explorer Support\n\nThe package makes use of the URL API, which is not provided in IE11 or earlier: https://caniuse.com/#feat=url\nMake sure to install the URL API polyfill (`npm install url-polyfill --save`) and add it into polyfills.ts:\n\n```\nimport 'url-polyfill';\n```\n\n\n## Examples\n\n#### File Upload\n\nA file upload service can be easily realized by adding a custom action for the POST-method, here's an example-implementation.\n\nAdd a ResourceAction for POST and an 'upload'-[ResourceActionMethod](#define-custom-action-methods) to your File-Service (Which we will then use in the component further down):\n\n\n```typescript\n@app/services/resource/file.resource.ts:\n\nimport { environment } from '../../../environments/environment';\n\nimport { Resource } from 'ngx-resource-factory/resource/resource';\nimport { ResourceConfiguration } from 'ngx-resource-factory/resource/resource-configuration';\nimport { ResourceInstance } from 'ngx-resource-factory/resource/resource-instance';\nimport { ResourceAction } from 'ngx-resource-factory/resource/resource-action';\nimport { ResourceActionMethod } from 'ngx-resource-factory/resource/resource-action-method';\nimport { ResourceActionHttpMethod } from 'ngx-resource-factory/resource/resource-action-http-method';\n\nexport class UploadableFile extends ResourceInstance {\n    pk: number;\n    parent_pk: number;\n}\n\n@Injectable()\n@ResourceConfiguration({\n    name: 'FileResource',\n    url: `${environment.api_url}/file/:pk/`,\n    pkAttr: 'pk',\n    instanceClass: UploadableFile,\n    stripTrailingSlashes: false,\n    dataAttr: 'results',\n    useDataAttrForList: true,\n    useDataAttrForObject: false,\n    totalAttr: 'count',\n})\nexport class FileResource extends Resource\u003cUploadableFile\u003e {\n\n    @ResourceAction({\n        method: ResourceActionHttpMethod.POST,\n        paramDefaults: [],\n        isList: false,\n        invalidateCache: true,\n    })\n    upload: ResourceActionMethod\u003cany, any, any\u003e;\n\n}\n```\n\nThe content-type will be automatically set by the browser.\n\n\nIn your component's upload-function, set up the payload with FormData() and append the file to it, which we will then POST to the backend with the 'upload'-ResourceActionMethod we have implemented in the service above:\n\n```typescript\n@app/screens/fileupload/fileupload.component.ts:\n[..]\nimport { FileResource } from '@app/services/resource/file.resource';\n\nexport class FileUploadComponent extends ModalBaseComponent implements OnInit, OnDestroy {\n    file: File;\n[..]\n\n    constructor(\n        public fileResource: FileResource\n    )\n\n[..]\n\n    onFileChange(event) {\n        if ( event.target.files.length \u003e 0 ) {\n            this.file = event.target.files[0]\n        }\n    }\n\n    uploadAppBinary() {\n        const payload: FormData = new FormData();\n        payload.append('path', this.file, this.file.name);\n        payload.append('parent_pk', this.parent.pk);\n        this.fileResource.upload({}, payload).$promise\n            .then((data) =\u003e {\n                console.log('Fileupload success:');\n                console.log(data);\n            })\n            .catch((reason) =\u003e {\n                console.log('Fileupload error:');\n                console.log(reason);\n            });\n    }\n```\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbeachmachine%2Fngx-resource-factory","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbeachmachine%2Fngx-resource-factory","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbeachmachine%2Fngx-resource-factory/lists"}