Skip to content

Normalized HTTP service

@nhtio/lucid-resourceful-vue-components/http

A single, consistent HTTP layer used across the library and available to your app via the IoC container. Use it to send requests in a uniform way, independent of whether the underlying implementation is Axios or Fetch.

Tip

This HTTP service is wired up by the IoC plugin. Make sure you’ve installed the IoC as shown in the Quickstart, then access the service with useHttp() from the composables module.

Imports you’ll use

From @nhtio/lucid-resourceful-vue-components/composables:

  • useHttp – get the active HTTP service instance.

From @nhtio/lucid-resourceful-vue-components/http:

  • ResourcefulHttpMethod – enum of HTTP methods.
  • Adapter classes for advanced customization: ResourcefulAxiosHttpService, ResourcefulFetchHttpService.
  • Types for typing your calls: ResourcefulHttpService, ResourcefulHttpResponse, ResourcefulHttpRequestOptions, ResourcefulHttpHeaders, ResourcefulHttpProgress, MaybePromised.
  • Middleware types: ResourcefulHttpRequestMiddlewareFn, ResourcefulHttpResponseMiddlewareFn, ResourcefulHttpMiddlewareProxy.
  • External adapter types for convenience: Axios, AxiosRequestConfig, KyInstance, KyRequestOptions, etc.

Basic usage

ts
import { useHttp } from '@nhtio/lucid-resourceful-vue-components/composables'
import { ResourcefulHttpMethod } from '@nhtio/lucid-resourceful-vue-components/http'

const http = useHttp()

// GET example
const users = await http.request<{ id: number; name: string }[]>({
  url: '/api/users',
  method: ResourcefulHttpMethod.GET,
})

// POST example
const created = await http.request<{ id: number }>({
  url: '/api/users',
  method: ResourcefulHttpMethod.POST,
  // body / payload shape depends on your backend
  // e.g., data, json, or body depending on adapter options
})

Notes:

  • The request options type is ResourcefulHttpRequestOptions.
  • The return type is Promise<ResourcefulHttpResponse<T>> where T is your expected data.
  • Progress support is represented by ResourcefulHttpProgress (availability depends on the adapter and the browser/runtime).

Resourceful encoding (default) vs plain mode

By default, this service is optimized for the Lucid Resourceful backend.

Default behavior (no plain flag):

  • Request bodies are encoded using the Resourceful encoding and sent with:
    • Content-Type: application/vnd.resourceful.structured; coding="zlib+base64";
    • x-resourceful-request-encoded: 1
    • x-resourceful-content-length: <bytes>
    • x-resourceful-response-encoded: 1
    • x-resourceful-for: resourceful-ui
  • Responses with the same content type are automatically decoded for you.
  • This mode is designed to integrate with Lucid Resourceful

If you need a standard body and headers, set plain: true in the request options:

ts
import { useHttp } from '@nhtio/lucid-resourceful-vue-components/composables'
import { ResourcefulHttpMethod } from '@nhtio/lucid-resourceful-vue-components/http'

const http = useHttp()

const res = await http.request<{ ok: boolean }>({
  url: '/api/standard-endpoint',
  method: ResourcefulHttpMethod.POST,
  headers: { 'Content-Type': 'application/json' },
  data: { name: 'Alice' },
  plain: true, // no special headers; body is not Resourceful-encoded
})

Middleware hooks (request/response)

You can customize behavior without replacing the whole HTTP service by adding middleware. This uses the @nhtio/middleware runner under the hood and exposes two chains on the service:

  • requestMiddleware: runs before a request is sent; mutate ResourcefulHttpRequestOptions in place
  • responseMiddleware: runs after a response is assembled (and decoded if applicable); mutate ResourcefulHttpResponse in place

Key points:

  • Middlewares receive mutable objects; changes persist downstream. The return value of the middleware function is ignored—call next() to continue.
  • Chains are composable and chainable via ResourcefulHttpMiddlewareProxy with .add(), .all(), .remove(), .clear(), .merge(), .has().
  • Works with both Axios and Fetch adapters uniformly.

Minimal example (make all requests plain and log):

ts
import { onMounted } from 'vue'
import { useHttp } from '@nhtio/lucid-resourceful-vue-components/composables'

onMounted(() => {
  const http = useHttp()
  http.requestMiddleware.add((c, n) => {
    c.plain = true
    console.log('HTTP Request:', c)
    n()
  })
})

Add an Authorization header:

ts
const http = useHttp()
const authMw = (opts, next) => {
  opts.headers = { ...opts.headers, Authorization: `Bearer ${token}` }
  next()
}

http.requestMiddleware.add(authMw)
// ... later, to remove
http.requestMiddleware.remove(authMw)

Measure timing with request/response middleware:

ts
const http = useHttp()
const timings = new Map<string, number>()

http.requestMiddleware.add((opts, next) => {
  timings.set(opts.url, performance.now())
  next()
})

http.responseMiddleware.add((res, next) => {
  const start = timings.get(res.url)
  if (start) console.debug('[http]', res.url, `${Math.round(performance.now() - start)}ms`)
  next()
})

Shape responses (e.g., turn 204 into null data):

ts
http.responseMiddleware.add((res, next) => {
  if (res.status === 204) res.data = null as any
  next()
})

Administration:

ts
// Clear all request middlewares
http.requestMiddleware.clear()

// Bulk load a set
http.requestMiddleware.all([
  (opts, next) => { /* ... */ next() },
  (opts, next) => { /* ... */ next() },
])

See the middleware library docs for advanced patterns: https://middleware.nht.io/

Customizing the HTTP implementation (optional)

The library ships with adapter classes for Axios and Fetch (via ky). If you need to swap the implementation or pass custom instances/options, replace the http service via the IoC:

ts
import { setIocService } from '@nhtio/lucid-resourceful-vue-components/ioc'
import { ResourcefulAxiosHttpService } from '@nhtio/lucid-resourceful-vue-components/http'
import type { Axios } from 'axios'

// Example: provide your own Axios instance
declare const axios: Axios

setIocService('http', () => new ResourcefulAxiosHttpService(/* pass axios or config here */))

Or wrap the current service to add cross‑cutting behavior (logging, metrics, retry):

ts
import { useIoC } from '@nhtio/lucid-resourceful-vue-components/composables'

const ioc = useIoC()

ioc.mutate('http', (current) => () => ({
  ...current,
  request: async (opts) => {
    const start = performance.now()
    const res = await current.request(opts)
    console.debug('[http]', opts.method, opts.url, `${Math.round(performance.now() - start)}ms`)
    return res
  },
}))

Types reference

From @nhtio/lucid-resourceful-vue-components/http:

  • ResourcefulHttpService
  • ResourcefulHttpResponse
  • ResourcefulHttpRequestOptions
  • ResourcefulHttpHeaders
  • ResourcefulHttpProgress
  • MaybePromised
  • ResourcefulHttpMethod
  • ResourcefulHttpRequestMiddlewareFn
  • ResourcefulHttpResponseMiddlewareFn
  • ResourcefulHttpMiddlewareProxy

External types re‑exported for convenience:

  • Axios: Axios, AxiosRequestConfig, AxiosProgressEvent, AxiosResponse
  • ky: KyInstance, KyRequestOptions, KyResponse

Quick reference

ts
// Get service in components/composables
import { useHttp } from '@nhtio/lucid-resourceful-vue-components/composables'

// Import method enum and types (optional)
import { ResourcefulHttpMethod, type ResourcefulHttpResponse } from '@nhtio/lucid-resourceful-vue-components/http'

If you don’t need to customize anything, just install the IoC and call useHttp() where you need it.