Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ NUXT_SSR=false
APP_BASE_URL=/

## Absolute or relative base url for API
#API_BASE_URL=https://petstore.swagger.io/v2
#API_BASE_URL=https://petstore3.swagger.io/api/v3
#API_BROWSER_BASE_URL=
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,11 @@
# Rest API

1. API typings are generated based on Swagger/OpenAPI provided by backend. See `generate:api` script inside `package.json`.
2. Use `$taxios` instead of `$axios`. WebStorm provides auto-completion and type checking for url, body, params and query.
2. Use `useApi` or `taxios` instead of `$axios`. WebStorm provides auto-completion and type checking for url, body, params and query.
See [taxios docs](https://github.com/simplesmiler/taxios/tree/master/packages/taxios) for details.
3. If you encounter an issue with generated types, you should:
- Report about Swagger/OpenAPI issue.
- Temporary use `$taxios.unsafe.<method>` instead of `$taxios.<method>` until Swagger/OpenAPI is fixed.
- Temporary use `petsApi.unsafe.<method>` instead of `petsApi.<method>` until Swagger/OpenAPI is fixed.

# Environment variables

Expand Down
19,668 changes: 309 additions & 19,359 deletions package-lock.json

Large diffs are not rendered by default.

13 changes: 7 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"dev": "nuxt-ts dev -c ./src/nuxt.config.ts",
"build": "shx rm -rf ./build && tsc -p ./tsconfig.build.json && nuxt-ts build -c ./src/nuxt.config.ts",
"start": "nuxt-start -c ./build/nuxt.config.js",
"generate:api": "taxios-generate https://petstore.swagger.io/v2/swagger.json -o ./src/types/generated/PetStore.ts -e PetStore && prettier --write ./src/types/generated/PetStore.ts",
"generate:api": "taxios-generate https://petstore3.swagger.io/api/v3/openapi.json -o ./src/types/generated/PetStore.ts -e PetStore && prettier --write ./src/types/generated/PetStore.ts",
"lint": "run-s -csn lint:eslint lint:stylelint lint:prettier",
"fix": "run-s -csn fix:eslint fix:stylelint fix:prettier",
"lint:prettier": "prettier --check .",
Expand All @@ -25,8 +25,9 @@
},
"license": "ISC",
"dependencies": {
"@nuxtjs/composition-api": "^0.20.1",
"@simplesmiler/taxios": "^0.2.6",
"@nuxtjs/composition-api": "^0.26.0",
"@simplesmiler/taxios": "^0.2.7",
"@vue/composition-api": "^1.0.5",
"core-js": "^3.8.3",
"nuxt-start": "^2.14.12",
"vue": "^2.6.12",
Expand All @@ -37,9 +38,9 @@
"@nuxt/types": "^2.14.12",
"@nuxt/typescript-build": "^2.0.4",
"@nuxt/typescript-runtime": "^2.0.1",
"@nuxtjs/axios": "5.13.0",
"@nuxtjs/axios": "^5.13.6",
"@nuxtjs/eslint-config-typescript": "^5.0.0",
"@simplesmiler/taxios-generate": "^0.2.6",
"@simplesmiler/taxios-generate": "^0.2.7",
"@web-bee-ru/commitlint-config": "^1.0.0",
"bootstrap": "^4.6.0",
"cookie-universal-nuxt": "^2.1.4",
Expand All @@ -58,7 +59,7 @@
"stylelint-config-recommended-scss": "^4.2.0",
"stylelint-prettier": "^1.1.2",
"stylelint-scss": "^3.19.0",
"typescript": "^4.1.5",
"typescript": "^4.3.5",
"vuex-module-decorators": "^1.0.1"
}
}
23 changes: 23 additions & 0 deletions src/components/api/ApiContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { InjectionKey, UnwrapRef } from '@nuxtjs/composition-api';
import { AxiosInstance } from 'axios';

import { NonStrictTaxios, PetsAxios, PetsTaxios } from '~/types/api';

import { nonStrictApi, nonStrictAxios, petsApi, petsAxios } from './defaults';

export interface ApiContextProps {
petsAxios: PetsAxios;
petsApi: PetsTaxios;
nonStrictAxios: AxiosInstance;
nonStrictApi: NonStrictTaxios;
}

export const defaultValue: ApiContextProps = {
petsAxios,
petsApi,
nonStrictAxios,
nonStrictApi,
};

// @NOTE: UnwrapRef -- because reactive() breaks source type
export const ApiContextSymbol: InjectionKey<UnwrapRef<ApiContextProps>> = Symbol('ApiContext');
54 changes: 54 additions & 0 deletions src/components/api/ApiProvider.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<script lang="ts">
import { computed, defineComponent, provide, reactive, useContext } from '@nuxtjs/composition-api';
import { Taxios } from '@simplesmiler/taxios';

import { PetStore } from '~/types/generated/PetStore';

import { ApiContextSymbol } from './ApiContext';

export default defineComponent({
props: {
petsApiBaseUrl: {
type: String,
required: true,
},
},
setup({ petsApiBaseUrl }, { slots }) {
const { $axios } = useContext();

const petsAxios = computed(() =>
$axios.create({
baseURL: petsApiBaseUrl,
}),
);

const petsApi = computed(() => new Taxios<PetStore>(petsAxios.value));

const nonStrictAxios = computed(() =>
$axios.create({
baseURL: '/',
}),
);

const nonStrictApi = computed(() => new Taxios<any, false>(nonStrictAxios.value));

// @NOTE: Context.Provider alternative
provide(
ApiContextSymbol,
reactive({
petsAxios,
petsApi,
nonStrictAxios,
nonStrictApi,
}),
);

return () => {
if (!slots.default) {
throw new Error('ApiProvider: default slot (children) is required');
}
return slots.default();
};
},
});
</script>
20 changes: 20 additions & 0 deletions src/components/api/defaults.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Taxios } from '@simplesmiler/taxios';
import Axios from 'axios';

import { PetStore } from '~/types/generated/PetStore';

export const petsAxios = Axios.create({
// @NOTE: Put base config here
baseURL: '/',
withCredentials: false,
});

export const nonStrictAxios = Axios.create({
// @NOTE: Put base config here
baseURL: '/',
withCredentials: false,
});

export const petsApi = new Taxios<PetStore>(petsAxios);

export const nonStrictApi = new Taxios<any, false>(nonStrictAxios);
14 changes: 14 additions & 0 deletions src/components/api/hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { inject } from '@nuxtjs/composition-api';

import { ApiContextSymbol, defaultValue } from './ApiContext';

/**
* Returns provided reactive object with your api
* @example
* // const { petsApi } = useApi() // bad usage, WON'T WORK!!
* const api = useApi() // right usage
* const { data } = await api.petsApi.get('/pet/findByStatus')
*/
export function useApi() {
return inject(ApiContextSymbol) ?? defaultValue;
}
5 changes: 5 additions & 0 deletions src/components/api/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export type { ApiContextProps } from './ApiContext';
export { ApiContextSymbol } from './ApiContext';
export { default as ApiProvider } from './ApiProvider.vue';
export * as defaults from './defaults';
export { useApi } from './hooks';
29 changes: 29 additions & 0 deletions src/layouts/default.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<template>
<ApiProvider :pets-api-base-url="petsApiBaseUrl">
<div>
<div class="nav">
<NuxtLink to="/" class="nav-link">Home</NuxtLink>
<NuxtLink to="/pets" class="nav-link">Pets</NuxtLink>
</div>
<Nuxt />
</div>
</ApiProvider>
</template>

<script lang="ts">
import { defineComponent, useContext } from '@nuxtjs/composition-api';

import { ApiProvider } from '~/components/api';

export default defineComponent({
components: { ApiProvider },
setup() {
const { $config } = useContext();

return {
petsApiBaseUrl:
(process.server ? $config.axios.baseURL : $config.axios.browserBaseURL) || $config.axios.baseURL,
};
},
});
</script>
28 changes: 22 additions & 6 deletions src/layouts/error.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,28 @@
<template>
<div>
<h4>Error</h4>
<pre>{{ JSON.stringify(error, null, 2) }}</pre>
</div>
<ApiProvider :pets-api-base-url="petsApiBaseUrl">
<div>
<h4>Error</h4>
<pre>{{ JSON.stringify(error, null, 2) }}</pre>
</div>
</ApiProvider>
</template>

<script lang="ts">
import { NuxtError } from '@nuxt/types';
import { defineComponent, PropType } from '@nuxtjs/composition-api';
export default defineComponent({ props: { error: { type: Object as PropType<NuxtError>, required: true } } });
import { defineComponent, PropType, useContext } from '@nuxtjs/composition-api';

import { ApiProvider } from '~/components/api';

export default defineComponent({
components: { ApiProvider },
props: { error: { type: Object as PropType<NuxtError>, required: true } },
setup() {
const { $config } = useContext();

return {
petsApiBaseUrl:
(process.server ? $config.axios.baseURL : $config.axios.browserBaseURL) || $config.axios.baseURL,
};
},
});
</script>
5 changes: 2 additions & 3 deletions src/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const environmentConfig = {
publicRuntimeConfig: {
// Example: `SERVICE_URL: process.env.SERVICE_URL || 'http://localhost:4000',`
axios: {
baseURL: process.env.API_BASE_URL || 'https://petstore.swagger.io/v2',
baseURL: process.env.API_BASE_URL || 'https://petstore3.swagger.io/api/v3',
browserBaseURL: process.env.API_BROWSER_BASE_URL,
},
env: (process.env.NODE_ENV || 'development') as 'production' | 'development',
Expand All @@ -39,7 +39,7 @@ declare module '@nuxt/types/config/runtime' {
}

const config: NuxtConfig = {
buildModules: ['@nuxt/typescript-build', '@nuxtjs/composition-api', '@nuxtjs/axios', 'cookie-universal-nuxt'],
buildModules: ['@nuxt/typescript-build', '@nuxtjs/composition-api/module', '@nuxtjs/axios', 'cookie-universal-nuxt'],

ssr: NUXT_SSR === 'true',

Expand All @@ -62,7 +62,6 @@ const config: NuxtConfig = {
},

plugins: [
{ src: '~/plugins/taxios', mode: 'all' },
{ src: '~/plugins/vue-toasted', mode: 'all' },
{ src: '~/plugins/prevent-dev-errors', mode: 'client' },
],
Expand Down
29 changes: 29 additions & 0 deletions src/pages/pets.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<template>
<div class="pages-pets">
<div>Available pets:</div>
<pre>{{ pets ? JSON.stringify(pets, null, 2) : 'loading...' }}</pre>
</div>
</template>

<script lang="ts">
import { defineComponent, onMounted, ref } from '@nuxtjs/composition-api';

import { useApi } from '~/components/api';
import { PetStore } from '~/types/generated/PetStore';

export default defineComponent({
setup() {
const api = useApi();

const pets = ref<PetStore.Pet[] | null>(null);

onMounted(() => {
api.petsApi.get('/pet/findByStatus', { query: { status: 'available' } }).then((res) => (pets.value = res.data));
});

return {
pets,
};
},
});
</script>
31 changes: 0 additions & 31 deletions src/plugins/taxios.ts

This file was deleted.

10 changes: 10 additions & 0 deletions src/types/api/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Taxios } from '@simplesmiler/taxios';
import { AxiosInstance } from 'axios';

import { PetStore } from '~/types/generated/PetStore';

export type PetsAxios = AxiosInstance;

export type PetsTaxios = Taxios<PetStore>;

export type NonStrictTaxios = Taxios<any, false>;
Loading