Frontend client
Create implementation and type files that exposes a client for a remote OpenAPI server, that uses fetch
and can run in any browser.
To create a client for a remote OpenAPI API, you can use the following command:
$ platformatic client http://example.com/to/schema/file --frontend --language <language> --name <clientname>
where <language>
can be either js
or ts
.
This will create two files clientname.js
(or clientname.ts
) and clientname-types.d.ts
for types.
clientname
by default is api
Usage
The implementation generated by the tool exports all the named operation found and a factory object.
Named operations
import { setBaseUrl, getMovies } from './api.js'
setBaseUrl('http://my-server-url.com') // modifies the global `baseUrl` variable
const movies = await getMovies({})
console.log(movies)
Factory
The factory object is called build
and can be used like this
import build from './api.js'
const client = build('http://my-server-url.com')
const movies = await client.getMovies({})
console.log(movies)
You can use both named operations and the factory in the same file. They can work on different hosts, so the factory does not use the global setBaseUrl
function.
Generated Code
The type file will look like this
export interface GetMoviesRequest {
'limit'?: number;
'offset'?: number;
// ... all other options
}
interface GetMoviesResponseOK {
'id': number;
'title': string;
}
export interface Api {
setBaseUrl(newUrl: string) : void;
getMovies(req: GetMoviesRequest): Promise<Array<GetMoviesResponseOK>>;
// ... all operations listed here
}
type PlatformaticFrontendClient = Omit<Api, 'setBaseUrl'>
export default function build(url: string): PlatformaticFrontendClient
The javascript implementation will look like this
let baseUrl = ''
/** @type {import('./api-types.d.ts').Api['setBaseUrl']} */
export const setBaseUrl = (newUrl) => { baseUrl = newUrl }
/** @type {import('./api-types.d.ts').Api['getMovies']} */
export const getMovies = async (request) => {
return await _getMovies(baseUrl, request)
}
async function _createMovie (url, request) {
const response = await fetch(`${url}/movies/`, {
method:'post',
body: JSON.stringify(request),
headers: {
'Content-Type': 'application/json'
}
})
if (!response.ok) {
throw new Error(await response.text())
}
return await response.json()
}
/** @type {import('./api-types.d.ts').Api['createMovie']} */
export const createMovie = async (request) => {
return await _createMovie(baseUrl, request)
}
// ...
export default function build (url) {
return {
getMovies: _getMovies.bind(url, ...arguments),
// ...
}
}
The typescript implementation will look like this
import type { Api } from './api-types'
import type * as Types from './api-types'
let baseUrl = ''
export const setBaseUrl = (newUrl: string) : void => { baseUrl = newUrl }
const _getMovies = async (url: string, request: Types.GetMoviesRequest) => {
const response = await fetch(`${url}/movies/?${new URLSearchParams(Object.entries(request || {})).toString()}`)
if (!response.ok) {
throw new Error(await response.text())
}
return await response.json()
}
export const getMovies: Api['getMovies'] = async (request: Types.GetMoviesRequest) => {
return await _getMovies(baseUrl, request)
}
// ...
export default function build (url) {
return {
getMovies: _getMovies.bind(url, ...arguments),
// ...
}
}