vue-composition-crud
v1.22.1
Published
CRUD API Composables for Vue
Downloads
36
Readme
Vue Composition CRUD
This package supplies modules and classes to allow for easy interaction with a CRUD-based API, including Vue Composition providers.
- Vue Composition CRUD
- Installation
- API Documentation
- Overview of Key Package Contents
- Basic Usage
- Examples
- Typescript
- Testing
Installation
yarn add vue-composition-crudAPI Documentation
Full API documentation is created with typedoc and can be generated by running yarn docs.
The latest full API documentation is generated as part of the CI/CD pipeline.
Documentation generated on demand is placed in the docs folder.
Overview of Key Package Contents
API
The API class supplies a layer to provide HTTP(S) operations, which can
be augmented with middleware.
The API class emits the following events:
authenticated- when an authentication provider handles the authentication operationauthentication-failed- when a request fails due to a401HTTP errordeauthenticated- when an authentication provider handles the deauthentication operationrequest-failed- when a request fails due to a different HTTP error
Middleware
Middlware classes are used to provide additional functionality when performing requests. This can include things like:
- performing authentication
- tweaking request and response URLs, headers, and content
- performing logging operations
The built-in middleware currently includes:
SessionAuthenticationMiddleware- authenticate with a username and password, and then persist the session with a cookie.TokenAuthenticationMiddleware- authenticate with either a username and password, or an access and/or refresh token, or an API key, and then persist the session by supplying a bearer token header with each request.CsrfTokenMiddleware- receive a CSRF token from a header, a cookie, or by supplying a custom function to retrieve the value, and then send the CSRF token when making requests by supplying it as a request header or injecting it into the body of the request.TrailingSlashMiddleware- tweak all outgoing URLs to either include or not include trailing slashes.PageMiddlware- advanced pagination features to allow you to use the built-in pagination class with APIs that don't supply objects in exactly the same way as expected. This allows for the use of an offset-limit style pagniation system, allows the transformation of query parameters, and allows for the response from the remote server to be mapped to an object that has the shape that this package expects.
Composables
useApi
useApi(options, middlewares) => {
api: Ref<CrudApi>
}Creates a new Api instance and returns it as a Ref.
useGlobalApi
useGlobalApi(options, middlewares) => {
api: Ref<CrudApi>
}The same as useApi, but creates a global instance. The first time you
call this, it will create the API instance and initialize the ref. Every
subsequent call to this function simply retrieves the initial ref.
I'd recommend using provide() and inject() over a global mechanism, but
some people are into it, so here you go.
useResource
useResource<ItemType>(api, resourceName) => {
isUnloaded: Ref<boolean>,
isLoading: Ref<boolean>,
isLoaded: Ref<boolean>,
isFailed: Ref<boolean>,
error: Ref<Error>,
item: Ref<ItemType>,
createItem(value: ItemType): Promise<ItemType>,
retrieveItem(id: string | number): Promise<ItemType>,
updateItem(id: string | number, value: ItemType): Promise<ItemType>,
deleteItem(id: string | number): Promise<void>,
}Create a resource to handle Create, Retrieve, Update, and Delete (CRUD) operations for a specific API resource.
The resourceName parameter is just the API endpoint name, and is appended to
the Base URL that is supplied when you create the Api instance with new Api({...})
or useApi({...}). For example, if your URL was https://www.example.com/api/users,
then the baseUrl would be https://www.example.com/api/, and the resourceName would
be users.
The four boolean refs are used to determine the current state of the resource.
isUnloadedis true when the resource has not yet been used.isLoadingis true when any CRUD operation is being performed.isLoadedis true when any CRUD operation completes successfully.isFailedis true when any CRUD operation fails.erroris the last error object thrown to cause the CRUD operation to fail.itemis set to the content of the resource when a create, retrieve, or update operation completes successfully.itemis cleared when a delete operation completes successfully.createItem,retrieveItem,updateItem, anddeleteItemcall upon the underlying API instance to perform the relevant queries. These queries match toPOST,GET,PATCH, andDELETEHTTP method operations.
useCollection
useCollection<ItemType>(api, resourceName) => {
isUnloaded: Ref<boolean>,
isLoading: Ref<boolean>,
isLoaded: Ref<boolean>,
isFailed: Ref<boolean>,
error: Ref<Error>,
items: Ref<Array<ItemType>>,
listItems(queryOptions): Promise<Array<ItemType>>,
}Create a collection to perform list operations against a specific API resource.
Most of the returned refs are the same as in useResource. The notable differences are
that:
- Instead of a single resource
item, you have an array ofitems - Instead of CRUD methods, you have a
listItemsmethod
The listItems method allows you to supply queryOptions, which can be used to
search and filter the resultset on the server side. For example:
const collection = useCollection
collection.listItems({search: "my search text", filter: {"name": "john", "age": "33"}})usePage
usePage<ItemType>(api, resourceName) => {
isUnloaded: Ref<boolean>,
isLoading: Ref<boolean>,
isLoaded: Ref<boolean>,
isFailed: Ref<boolean>,
error: Ref<Error>,
page: Ref<Page<ItemType>>,
items: Ref<Array<ItemType>>,
listItems(queryOptions): Promise<Page<ItemType>>,
}Much the same as useCollection, but instead of expecting an array of items,
this expects a Page. One page supplies a subset of results, as well as some
extra details like what the next page is, the total number of pages, and any
metadata that the remote server might like to supply.
The items ref will be updated with the current set of items based on the page
that is being viewed.
The expected structure of a Page response is:
{
page: {
previous?: number;
current: number;
next?: number;
last?: number;
};
items: Array<ItemType>;
meta?: unknown;
}Basic Usage
/*
* symbols.ts
*/
// Define the `API` symbol, which is used to provide
// and inject an api instance in Vue components.
export const API = Symbol("API");<!--
-- App.vue
-->
<template>
...
</template>
<script lang="ts">
import { ref, provide, defineComponent } from "vue";
import { useApi } from "vue-composition-crud";
import { API } from "./symbols.ts"
export default defineComponent({
setup() {
// Create an API instance.
// Note that the `useApi` composition method gives
// you a Ref<CrudApi> instance so to use it you will
// need to call `api.value.xxxx()`
const { api } = useApi({
baseUrl: "https://www.example.com/api/",
});
// Supply the `api` instance to all children using
// the `API` symbol as a key.
provide(API, api);
return {};
}
})
</script><!--
-- UserInformation.vue
-->
<template>
<div v-if="resource.isLoading.value">Loading - just a moment...</div>
<div v-if="resource.isFailed.value">Loading failed: {{ resource.error.value }}</div>
<div v-if="resource.isLoaded.value">
<h1>{{ user.name }}</h1>
<h2>{{ user.age }} years old</h2>
<address>{{ user.address }}</address>
<div>
<a :href="'mailto:' + user.email">{{ user.email }}</a>
</div>
</div>
</template>
<script lang="ts">
import { Ref, inject, defineComponent, onMounted } from "vue";
import { useApi, useResource, CrudApi } from "vue-composition-crud";
import { CrudApi } from "vue-composition-crud/api/types";
import { API } from "./symbols.ts"
export default defineComponent({
setup() {
// Inject the `api` instance from the parent context.
// Remember that this is a `Ref<CrudApi>` instance.
const api = inject(API) as Ref<CrudApi>;
// Use the API *value* to set up the useful composition
// elements like lists, pages, and resources.
const resource = useResource(api.value, "users");
// When the component is mounted, load user #123
onMounted(() => {
resource.retrieve(123)
})
// Supply the interesting stuff (e.g., the resource) to
// the component.
return {
resource,
user: resource.item.value,
}
},
})
</script>Examples
Typescript
This package is developed in typescript, compiled down to javascript, and supplies declaration files.
Testing
This package uses mocha and chai for testing.
Tests can be run with yarn test and code coverage can be generated with yarn coverage.
The latest coverage reports are generated as part of the CI/CD pipeline.
