TypeScript friendly HTTP client wrapper for the browser and node.js.
Breaking change (2020/06/16) :warning:
Since aspida >= 0.18.0
, the property data
of the request and response has been changed to body
.
const { body } = await client.v1.users.post({ body: { name: "taro" } })
const body = await client.v1.users.$post({ body: { name: "taro" } })
The modules affected by this change
- @aspida/axios >=
0.8.0
- @aspida/ky >=
0.6.0
- @aspida/fetch >=
0.6.0
- @aspida/node-fetch >=
0.5.0
- openapi2aspida >=
0.8.0
Features
- Path, URL query, header, body, and response can all specify the type
- FormData / URLSearchParams content can also specify the type
- HTTP client supports axios / ky / ky-universal / fetch / node-fetch
- Path definition is the same naming convention as Nuxt.js pages
Procedure
- Reproduce the endpoint directory structure in the apis directory
- Export a Type alias named "Methods"
- Call 'aspida --build' with npm scripts
- API type definition file 'apis/$api.ts' will be generated, so import the application and make an HTTP request
Getting Started
Installation (axios ver.)
Create apis directory
$ mkdir apis
Create an endpoint type definition file
-
GET: /v1/users/?limit={number}
-
POST: /v1/users
apis/v1/users/index.ts
type User = {
id: number
name: string
}
export type Methods = {
get: {
query?: {
limit: number
}
resBody: User[]
}
post: {
reqBody: {
name: string
}
resBody: User
}
}
-
GET: /v1/users/${userId}
-
PUT: /v1/users/${userId}
apis/v1/users/_userId@number.ts
Specify the type of path variable “userId” starting with underscore with “@number”
If not specified with @, the default path variable type is "number | string"
type User = {
id: number
name: string
}
export type Methods = {
get: {
resBody: User
}
put: {
reqBody: {
name: string
}
resBody: User
}
}
Build type definition file
package.json
{
"scripts": {
"api:build": "aspida --build"
}
}
$ npm run api:build
> apis/$api.ts was built successfully.
Make HTTP request from application
src/index.ts
import aspida from "@aspida/axios"
import api from "../apis/$api"
;(async () => {
const userId = 0
const limit = 10
const client = api(aspida())
await client.v1.users.post({ body: { name: "taro" } })
const res = await client.v1.users.get({ query: { limit } })
console.log(res)
const user = await client.v1.users._userId(userId).$get()
console.log(user)
})()
aspida - DEV Community
Learn more about HTTP clients
Command Line Interface Options
Option | Type | Default | Description |
---|
--build
-b | | |
Generate $api.ts required for
aspida routing.
|
--config
-c | string | "aspida.config.js" | Specify the path to the configuration file. |
--watch
-w | | |
Enable watch mode.
Regenerate $api.ts according to
the increase / decrease of the API endpoint file.
|
--version
-v | | | Print aspida version. |
Options of aspida.config.js
Option | Type | Default | Description |
---|
input | string | "apis", "server/api", "api" | Specifies the endpoint type definition root directory |
baseURL | string | "" | Specify baseURL of the request |
trailingSlash | boolean | false | Append / to the request URL |
outputEachDir | boolean | false | Generate $api.ts in each endpoint directory |
Tips
Change the directory where type definition file is placed to other than apis
Create a configuration file at the root of the project
aspida.config.js
module.exports = { input: "src" }
Specify baseURL in configuration file
module.exports = { input: "apis", baseURL: "https://example.com/api" }
If you want to define multiple API endpoints, specify them in an array
module.exports = [{ input: "api1" }, { input: "api2", baseURL: "https://example.com/api" }]
Serialize GET parameters manually
aspida leaves GET parameter serialization to standard HTTP client behavior
If you want to serialize manually, you can use config object of HTTP client
src/index.ts
import axios from "axios"
import qs from "qs"
import aspida from "@aspida/axios"
import api from "../apis/$api"
;(async () => {
const client = api(
aspida(axios, { paramsSerializer: params => qs.stringify(params, { indices: false }) })
)
const users = await client.v1.users.$get({
query: { ids: [1, 2, 3] }
})
console.log(users)
})()
POST with FormData
apis/v1/users/index.ts
export type Methods = {
post: {
reqFormat: FormData
reqBody: {
name: string
icon: Blob
}
resBody: {
id: number
name: string
}
}
}
src/index.ts
import aspida from "@aspida/axios"
import api from "../apis/$api"
;(async () => {
const client = api(aspida())
const user = await client.v1.users.$post({
body: {
name: "taro",
icon: imageBlob
}
})
console.log(user)
})()
POST with URLSearchParams
apis/v1/users/index.ts
export type Methods = {
post: {
reqFormat: URLSearchParams
reqBody: {
name: string
}
resBody: {
id: number
name: string
}
}
}
src/index.ts
import aspida from "@aspida/axios"
import api from "../apis/$api"
;(async () => {
const client = api(aspida())
const user = await client.v1.users.$post({ body: { name: "taro" } })
console.log(user)
})()
Receive response with ArrayBuffer
apis/v1/users/index.ts
export type Methods = {
get: {
query: {
name: string
}
resBody: ArrayBuffer
}
}
src/index.ts
import aspida from "@aspida/axios"
import api from "../apis/$api"
;(async () => {
const client = api(aspida())
const user = await client.v1.users.$get({ query: { name: "taro" } })
console.log(user)
})()
Convert from OpenAPI / Swagger
aspida.config.js
module.exports = {
input: "apis",
openapi: { inputFile: "https://petstore.swagger.io/v2/swagger.json" }
}
tarminal
$ npx openapi2aspida --build
Docs of openapi2aspida
Define endpoints that contain special characters
Special characters are encoded as percent-encoding in the file name
Example ":"
-> "%3A"
apis/foo%3Abar.ts
export type Methods = {
get: {
resBody: string
}
}
With clients, "%3A"
-> "_3A"
src/index.ts
import aspida from "@aspida/axios"
import api from "../apis/$api"
;(async () => {
const client = api(aspida())
const message = await client.foo_3Abar.$get()
console.log(message)
})()
Import only some endpoints
If you don't need to use all of apis/$api.ts
, you can split them up and import only part of them
outputEachDir
option generates $api.ts
in each endpoint directory
$api.ts
will not be generated under the directory containing the path variable
aspida.config.js
module.exports = {
input: "apis",
outputEachDir: true
}
Import only $api.ts
of the endpoint you want to use and put it into Object
src/index.ts
import aspida from "@aspida/axios"
import api0 from "../apis/v1/foo/$api"
import api1 from "../apis/v2/bar/$api"
;(async () => {
const aspidaClient = aspida()
const client = {
foo: api0(aspidaClient),
bar: api1(aspidaClient)
}
const message = await client.bar._id(1).$get()
})()
Support
License
aspida is licensed under a MIT License.