{"id":15591,"library":"devour-client","title":"Devour JSON-API Client","description":"Devour Client is a lightweight, framework-agnostic JavaScript client for consuming JSON:API compliant APIs. It simplifies the often painful process of manually serializing and deserializing JSON:API resources, providing clear conventions for pagination, filtering, sparse fields, and relationships. Currently stable at version 3.2.0, it focuses on offering a simple yet comprehensive feature set that differentiates it from other JavaScript JSON:API client implementations by abstracting away the complexities of the specification. While a specific release cadence isn't defined, the project sees regular maintenance and dependency updates. It provides a flexible middleware stack and configurable options for common API patterns like pluralization, trailing slashes, and authentication.","status":"active","version":"3.2.0","language":"javascript","source_language":"en","source_url":"https://github.com/devour-js/devour-client","tags":["javascript","Devour","JSON-API","API","Client"],"install":[{"cmd":"npm install devour-client","lang":"bash","label":"npm"},{"cmd":"yarn add devour-client","lang":"bash","label":"yarn"},{"cmd":"pnpm add devour-client","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Used by default for resource name pluralization; can be overridden or disabled.","package":"pluralize","optional":true}],"imports":[{"note":"Devour Client is primarily consumed as an ES module, though CommonJS usage might work in older Node environments, ESM is the recommended and modern approach.","wrong":"const JsonApi = require('devour-client')","symbol":"JsonApi","correct":"import JsonApi from 'devour-client'"},{"note":"The `apiUrl` option is mandatory for instantiating the client to specify the API endpoint.","wrong":"const jsonApi = new JsonApi()","symbol":"JsonApi","correct":"const jsonApi = new JsonApi({ apiUrl: 'http://your-api-here.com' })"}],"quickstart":{"code":"import JsonApi from 'devour-client'\n\n// Bootstrap the client with your API endpoint\nconst jsonApi = new JsonApi({apiUrl:'http://your-api-here.com'})\n\n// Define a model schema matching your JSON:API resources\njsonApi.define('post', {\n  title: '',\n  content: '',\n  tags: [],\n  comments: {\n    jsonApi: 'hasMany',\n    type: 'comments'\n  }\n})\n\njsonApi.define('comment', {\n  comment: '',\n  post: {\n    jsonApi: 'belongsTo',\n    type: 'posts'\n  }\n})\n\nasync function runExample() {\n  try {\n    // Fetch all posts with pagination\n    const postsPage2 = await jsonApi.findAll('post', {page: {number: 2}});\n    console.log('Posts on page 2:', postsPage2.data.map(p => p.title));\n\n    // Fetch a single post by ID\n    const post = await jsonApi.find('post', '5');\n    console.log('Post 5:', post.data.title);\n\n    // Create a new post\n    const newPost = await jsonApi.create('post', {\n      title: 'Hello from Devour!',\n      content: 'This is some content for a new post.',\n      tags: ['devour', 'jsonapi']\n    });\n    console.log('Created post:', newPost.data.title);\n\n    // Update an existing post\n    const updatedPost = await jsonApi.update('post', {\n      id: newPost.data.id,\n      title: 'Updated title',\n      content: 'New content for the updated post',\n      tags: ['devour', 'update']\n    });\n    console.log('Updated post:', updatedPost.data.title);\n\n    // Delete a post\n    await jsonApi.destroy('post', updatedPost.data.id);\n    console.log('Deleted post:', updatedPost.data.id);\n\n    // Make an arbitrary request\n    const customRequest = await jsonApi.request('http://your-api-here.com/some-custom-endpoint', 'GET', { queryParam: 'value' });\n    console.log('Custom request result:', customRequest);\n\n  } catch (error) {\n    console.error('API Error:', error.errors || error.message);\n  }\n}\n\nrunExample();\n","lang":"javascript","description":"This quickstart initializes Devour Client, defines two JSON:API models ('post' and 'comment'), and demonstrates common CRUD operations (findAll, find, create, update, destroy) and arbitrary requests against a hypothetical API endpoint."},"warnings":[{"fix":"Only use `disableErrorsForMissingResourceDefinitions: true` if you have a robust strategy for handling undefined resources. Otherwise, ensure all expected JSON:API resource types are defined using `jsonApi.define()`.","message":"Enabling `disableErrorsForMissingResourceDefinitions` can mask issues where your API returns resources not explicitly defined in your client-side models, leading to unexpected data handling or UI errors.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Pass `pluralize: false` to the `JsonApi` constructor to disable, or provide a custom pluralization function: `new JsonApi({apiUrl: '...', pluralize: myCustomPluralizeFunc})`.","message":"By default, Devour Client uses the `pluralize` package for converting singular model names (e.g., 'post') to plural API endpoints (e.g., '/posts'). Inconsistent pluralization between your client and API can lead to 404 errors. If your API uses different pluralization rules or singular resource paths, you must configure or disable this behavior.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"If you need to maintain builder state across calls, set `resetBuilderOnCall: false` in the `JsonApi` constructor options. Be mindful of managing the builder state manually if you disable this.","message":"The `resetBuilderOnCall` option defaults to `true`, which clears the query builder stack after each `get`, `post`, `patch`, or `destroy` call. If you intend to chain multiple operations or reuse parts of a builder for subsequent requests without re-initializing, you might get unexpected results.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Regularly check the Snyk badge or run `npm audit` and `snyk test` on your project dependencies. Update `devour-client` to the latest version to ensure you have security patches for any known vulnerabilities.","message":"Devour Client's GitHub repository indicates 'Known Vulnerabilities' through Snyk. While specific CVEs are not detailed in the provided information, developers should be aware that dependencies or the client itself may have had or currently have security issues.","severity":"breaking","affected_versions":"*"}],"env_vars":null,"last_verified":"2026-04-21T00:00:00.000Z","next_check":"2026-07-20T00:00:00.000Z","problems":[{"fix":"Define the missing resource model: `jsonApi.define('comments', { comment: '', post: { jsonApi: 'belongsTo', type: 'posts' } })` or ensure `disableErrorsForMissingResourceDefinitions` is set to `true` if you wish to suppress these errors.","cause":"Attempting to interact with a JSON:API resource type (e.g., 'comments') that has not been defined using `jsonApi.define('comments', { ... })` in your client initialization.","error":"Error: Resource 'comments' not defined in Devour's model directory."},{"fix":"Verify the `apiUrl` is correct and accessible. Check your browser's console for CORS errors. Ensure your API server is running and reachable from the client's environment.","cause":"This generic network error usually indicates that the client could not connect to the `apiUrl` specified, either due to incorrect URL, CORS issues, network problems, or the API server being down.","error":"Failed to fetch"},{"fix":"Pass the necessary authentication details to the `JsonApi` constructor: `new JsonApi({ apiUrl: '...', bearer: 'YOUR_TOKEN' })` or `new JsonApi({ apiUrl: '...', auth: { username: 'user', password: 'pass' } })`.","cause":"The API endpoint requires authentication, and the request was sent without proper authorization headers (e.g., bearer token, basic auth).","error":"Response code 401 (Unauthorized)"}],"ecosystem":"npm"}