{"id":21991316,"url":"https://github.com/jhony-v/api-entity","last_synced_at":"2025-03-23T03:28:19.577Z","repository":{"id":63583081,"uuid":"567882542","full_name":"jhony-v/api-entity","owner":"jhony-v","description":"♒ Create service entities according to your API requests, agnostic to the framework you are using and fully typed","archived":false,"fork":false,"pushed_at":"2022-12-06T14:12:17.000Z","size":919,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-11T11:09:27.819Z","etag":null,"topics":["api-client","axios","browser","fetch","http","models","promise"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/api-entity","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jhony-v.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-11-18T20:11:32.000Z","updated_at":"2023-03-07T13:00:00.000Z","dependencies_parsed_at":"2023-01-23T08:10:21.294Z","dependency_job_id":null,"html_url":"https://github.com/jhony-v/api-entity","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jhony-v%2Fapi-entity","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jhony-v%2Fapi-entity/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jhony-v%2Fapi-entity/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jhony-v%2Fapi-entity/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jhony-v","download_url":"https://codeload.github.com/jhony-v/api-entity/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245052624,"owners_count":20553161,"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":["api-client","axios","browser","fetch","http","models","promise"],"created_at":"2024-11-29T20:08:15.421Z","updated_at":"2025-03-23T03:28:19.554Z","avatar_url":"https://github.com/jhony-v.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/static/img/entity.png\" width=\"300\" /\u003e\n\u003c/p\u003e\n\n# api-entity\n\nCreate service entities according to your API agnostic to the framework you are using **[full documentation](https://jhony-v.github.io/api-entity/).**\n\n## Problem\n\nNowadays, our FrontEnd applications use countless endpoints, despite dividing them into multiple layers or entities, but there is still a problem because of the quantity of boilerplate we need to write, bind the URL, create methods, pass parameters, and so on. Therefore, the following implementation mostly removes these problems through an intuitive API.\n\n## Usage\n\n### Installation\n\nUse the following command line to add this dependency in your app.\n\n```console\nyarn add api-entity\n```\n\n### Native request\n\nUsing native requests and passing directly the path, It works with GET methods.\n\n```ts\nimport { createServiceEntity } from \"api-entity\";\n\nconst posts = createServiceEntity({\n  baseUrl: \"https://jsonplaceholder.typicode.com\",\n  entity: \"posts\",\n  actions: {\n    all: \"/\",\n    byId: \"/:id\",\n    byIdComments: \"/:id/comments\",\n    postComments: async ({ actions, params }) =\u003e {\n      const post = await actions.byId(params);\n      const comments = await actions.byIdComments(params);\n      return {\n        post,\n        comments,\n      };\n    },\n  },\n});\n\nposts.all().then(console.log);\nposts.byId({ id: 1 }).then(console.log);\nposts.byIdComments({ id: 2 }).then(console.log);\nposts.postComments({ id: 3 }).then(console.log);\n```\n\n### Using external adapter\n\nUsing axios as an adapter or if you prefer another, you'll be able to do it.\n\n```ts\nimport axios from \"axios\";\nimport { createServiceEntity } from \"api-entity\";\n\n// Custom service with axios\nconst placeholderService = axios.create({\n  baseURL: \"https://jsonplaceholder.typicode.com\",\n});\n\nconst posts = createServiceEntity({\n  entity: \"posts\",\n  actions: {\n    byId: {\n      path: \"/:id\",\n    },\n    all: {\n      path: \"/\",\n      resolve: (value) =\u003e value.data,\n    },\n    create: {\n      path: \"/\",\n      type: \"post\",\n    },\n    update: {\n      path: \"/:id\",\n      type: \"put\",\n    },\n    delete: {\n      path: \"/:id\",\n      type: \"delete\",\n    },\n  },\n  adapter: placeholderService,\n});\n\nposts.all().then(console.log);\nposts.byId({ id: 1 }).then(console.log);\n```\n\n## API\n\n### entity\n\nName the base URL that will be attached to the action's path. Let's see some examples below.\n\n- posts:\n  - `/posts`\n  - `/posts/1`\n  - `/posts/1/comments`\n- comments:\n  - `/comments`\n  - `/comments/top`\n\n### baseUrl\n\nBase URL of the endpoint; when you create this one, this will be automatically attached alongside the entity and action's path properties automatically.\n\nLet's take a handful of the initial example and see how that resolves it.\n\n```ts\nconst posts = createServiceEntity({\n  baseUrl: \"https://jsonplaceholder.typicode.com\",\n  entity: \"posts\",\n  actions: {\n    all: \"/\", // Internally create the path: https://jsonplaceholder.typicode.com/posts/\n  },\n});\n```\n\n\u003e If you are using an adapter, you don't require adding that property 🤓.\n\n### actions\n\nHere, actions are part fundamental to modeling our API requests indeed.\n\nEach action corresponds to a specific endpoint, likewise, these can be declared in three distinct manners.\n\n1. Using the path\n\n```ts\nconst posts = createServiceEntity({\n  actions: {\n    all: \"/\",\n    byId: \"/:id\",\n    summary: \"/summary\",\n    byIdComments: \"/:id/comments\",\n  },\n});\n```\n\n2. Using an object customizable\n\n```ts\nconst posts = createServiceEntity({\n  actions: {\n    all: {\n      path: \"/\", // You don't need to add the type \"get\", default it is\n    },\n    add: {\n      path: \"/\",\n      type: \"post\",\n    },\n    byIdComments: {\n      path: \"/:id/comments\",\n      // Optional whether you want to manipulate the response and return a new data\n      resolve: (value) =\u003e value.data,\n    },\n  },\n});\n```\n\n3. Creating functions for complex manipulations\n\n```ts\nconst posts = createServiceEntity({\n  actions: {\n    postComments: async ({ actions, params }) =\u003e {\n      const post = await actions.byId(params);\n      const comments = await actions.byIdComments(params);\n      return {\n        post,\n        comments,\n      };\n    },\n  },\n});\n```\n\n### abort\n\nIf you desire to abort some actions for some reason, executing them is pretty straightforward.\n\nTo revoke a request, you have the property \"abort\", followed by the method's name.\n\n```ts\nconst posts = createServiceEntity({\n  actions: {\n    all: \"/\",\n    byId: \"/:id\",\n  },\n});\n\nposts.all().then(console.log);\nposts.abort.all(); // abort request of \"all\" method\nposts.byId({ id: 1 }).then(console.log);\nposts.abort.byId(); // abort request of \"byId\" method\n```\n\n### action utils\n\nAnother alternative to avoid creating nested structures with the type and URL is using these functions.\n\n| action | type   |\n| ------ | ------ |\n| get    | GET    |\n| post   | POST   |\n| put    | PUT    |\n| patch  | PATCH  |\n| del    | DELETE |\n\nHere I'm using the example above by replacing the object configuration with helper functions.\n\n```ts\nimport { put, post, get } from \"api-entity\";\n\nconst posts = createServiceEntity({\n  actions: {\n    all: get(\"/\"),\n    update: put(\"/:id\"),\n    add: post(\"/\"),\n    byIdComments: get(\"/:id/comments\", (value) =\u003e value.data),\n  },\n});\n```\n\n### adapter\n\nIf you are usually accustomed to using an external library like Axios, you can pass the instance to the adapter property, and it will be resolved internally.\n\n## Using types\n\nActions automatically will resolve async functions with generic types. But it's entirely possible to pass a custom type or interface to overwrite the default definitions.\n\n```ts\nimport { put, post, get } from \"api-entity\";\n\ntype Params = { id: string };\ntype Payload = {\n  title: string;\n};\n\ninterface PostService {\n  all(): Promise\u003cobject[]\u003e;\n  byId(params: Params): Promise\u003cobject\u003e;\n  update(params: Params \u0026 Payload): Promise\u003cobject\u003e;\n  add(payload: Payload): Promise\u003cobject\u003e;\n}\n\nconst posts = createServiceEntity\u003cPostService\u003e({\n  actions: {\n    all: get(\"/\"),\n    byId: get(\"/:id\"),\n    update: put(\"/:id\"),\n    add: post(\"/\"),\n  },\n});\n```\n\n### configureServiceEntity\n\nAnother approach to getting a centralized store is using a configuration that wraps multiple entities and resolves them with the same adapter, base URL, or global settings. The entities will be instanced once created this function and won't be reflected on performance.\n\nEach entity's property will be used as the entity property. Therefore, you can use it by accessing through the same name and calling their methods.\n\n```ts\nimport { post, get, createServiceEntity, configureServiceEntity } from \"api-entity\";\n\nconst posts = createServiceEntity({\n  actions: {\n    all: get(\"/\"),\n    byId: get(\"/:id\"),\n    add: post(\"/\"),\n  },\n});\n\nconst users = createServiceEntity({\n  actions: {\n    all: \"/\",\n    byId: \"/:id\",\n  },\n});\n\nconst services = configureServiceEntity({\n  baseUrl: \"https://jsonplaceholder.typicode.com\",\n  entities: { posts, users },\n});\n\n// https://jsonplaceholder.typicode.com/users/\nservices.users.all().then(console.log);\n\n// https://jsonplaceholder.typicode.com/posts/\nservices.posts.all().then(console.log);\n```\n\n[View a full example here 👈](https://codesandbox.io/s/api-entity-example-6twbrv)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjhony-v%2Fapi-entity","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjhony-v%2Fapi-entity","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjhony-v%2Fapi-entity/lists"}