Hi,
I write my own DTO (Data Transef Object) based on axios router. I need create an instance of my DTO client and set token per request/user on server and i want use that client on both (client and server).
import { Client } from '@caloriosa/dto'
// I need available request, document and app here (on server-side request and on client-side document)
let client = new Client({
url: "my.api.url",
token: req.cookies.token || document.cookies.token
}
app.$client = client;
So I have no idea where to create my client instance. I need avaliable $client in application on client and on server per request (because token, user identification).
Thanks.
PS: I can't use auth module or axios module, i written own DTO service and I need use it in my project.
You can use middleware which will be called before each route in Client Side or SSR.
Then create client in only server side maybe sth like:
import { Client } from '@caloriosa/dto'
export default function ({ app, req }) {
// ...
if (process.server) {
app.$client = client;
}
}
Thanks, it works, but:
I fetched my data in page via asyncData, it works
asyncData({ app }) {
app.$client.users.fetchUsers();
}
But in component components/myComp.vue I got Cannot read property 'users' of undefined
mounted() {
this.fillData(this.$client.users.fetchUsers(););
}
My middleware middleware/dto.js
import { createApiClient } from '@caloriosa/rest-dto'
export default function ({ app, req }) {
let client = createApiClient();
if (process.server) {
app.$client = client;
}
}
In nuxt.config.js
router: {
middleware: [
'dto'
]
}
How i can access to $client in components? I tried use in middleware app.$client = client without that if, but still not works :(
PS: I can access to $client in store?
I suggest you to put client into store, so that it can be used in anywhere.
Still i got Cannot read property 'users' of undefined from component, but in the page it's works.
Middleware
export default function ({ store, req }) {
let client = createApiClient();
store.$client = client;
}
myComp
mounted() {
this.fillData(this.$store.$client.users.fetchUsers())
}
store is instance of Vuex, you need to declare the state and use $store.state.
I got Cannot read property 'fetchUsers' of undefined but in server parent of fetchUsers exists.
store
export const state = () => ({
api: null
})
export const mutations = {
setApiClient (state, api) {
state.api = api
console.log(state.api);
}
}
middleware
import { createApiClient } from '@caloriosa/rest-dto'
export default function ({ store, req }) {
let api = createApiClient();
store.commit('setApiClient', api);
}
Vuexstore changes structure of my client object?
Dump from server:
API {
domain: null,
_events: {},
_eventsCount: 0,
_maxListeners: undefined,
_client:
Client {
_options:
{ url: 'http://localhost:6060',
token: null,
appSignature: null,
proxy: null },
url: 'http://localhost:6060',
_token: null,
_appSignature: null,
emiter:
EventEmitter {
domain: null,
_events: {},
_eventsCount: 0,
_maxListeners: undefined },
defaultArgs:
{ baseURL: 'http://localhost:6060',
headers: [Object],
proxy: null } },
_services: {} }
Dump from client:
{鈥
domain
:
(...)
_client
:
(...)
_events
:
(...)
_eventsCount
:
(...)
_services
:
(...)
__ob__
:
Observer {value: {鈥, dep: Dep, vmCount: 0}
get domain
:
茠 reactiveGetter()
set domain
:
茠 reactiveSetter(newVal)
get _client
:
茠 reactiveGetter()
set _client
:
茠 reactiveSetter(newVal)
get _events
:
茠 reactiveGetter()
set _events
:
茠 reactiveSetter(newVal)
get _eventsCount
:
茠 reactiveGetter()
set _eventsCount
:
茠 reactiveSetter(newVal)
get _services
:
茠 reactiveGetter()
set _services
:
茠 reactiveSetter(newVal)
__proto__
:
Object
It's different.
Oh my mistake, sorry, you can remove the store and keep a empty store/index.js, and remove the process.server
export default {
asyncData({ app }) {
app.$client.users.fetchUsers();
},
mounted() {
console.log(this.$store.app.$client)
}
}
console.log(this.$store.app.$client)
returns undefined
Maybe I have something wrong with middleware?
export default function ({ app, req }) {
let client = createApiClient();
if (process.server) {
app.$client = client;
}
}
I removed store/index.js
Okay, I uploaded it to git repo: https://github.com/Caloriosa/reporter
Server data fetch is here: https://github.com/Caloriosa/reporter/blob/41e187fc3ef4e8c99a13f79d7883eae8f7653223/pages/index.vue#L14
Component data fetch on client: https://github.com/Caloriosa/reporter/blob/41e187fc3ef4e8c99a13f79d7883eae8f7653223/components/graphs/TemperatureGraph.vue#L22
Middleware: https://github.com/Caloriosa/reporter/blob/master/middleware/dto.js
I want fetch data to page (about users, devices and etc) - server-side - calls rest api from server
And generate graphs - client-side - in components, calls rest api from client
I calling rest users.fetchUsers() for a test if it's works.
Keep store/index.js as an empty file and remove if (process.server)
my store/index.js is empty https://github.com/Caloriosa/reporter/blob/master/store/index.js
and I removed process.server and stil it's not works, still got undefined (2x)
https://github.com/Caloriosa/reporter/commit/f11d084958442d652b07800f0360b5636be3186d

It because of middleware will be executed in server side at first access, so client will not get the $api, you can also add a ssr:false plugin to set $api in first access.
So I must copy code $api init to a plugin? I try it. Thanks.
Wtf? I got an error while build:
TypeError: arguments[i].apply is not a function
- Tapable.js:375 Compiler.apply
[reporter]/[tapable]/lib/Tapable.js:375:16
- webpack.js:33 webpack
[reporter]/[webpack]/lib/webpack.js:33:19
- builder.js:418
[reporter]/[nuxt]/lib/builder/builder.js:418:24
- builder.js:417 Builder._callee5$
[reporter]/[nuxt]/lib/builder/builder.js:417:22
- builder.js:173 Builder._callee$
[reporter]/[nuxt]/lib/builder/builder.js:173:16
nuxt.config.js
module.exports = {
/*
** Headers of the page
*/
head: {
title: 'my-site',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: 'Nuxt.js project' }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
]
},
router: {
middleware: [
'dto'
]
},
/*
** Customize the progress bar color
*/
loading: { color: '#3B8070' },
/*
** Build configuration
*/
build: {
plugins: [
{ src: '~/plugins/dto', ssr: false }
],
/*
** Run ESLint on save
*/
extend (config, ctx) {
if (ctx.dev && ctx.isClient) {
config.module.rules.push({
enforce: 'pre',
test: /\.(js|vue)$/,
loader: 'eslint-loader',
exclude: /(node_modules)/
})
}
}
}
}
plugins/dto.js
import { createApiClient } from '@caloriosa/rest-dto'
export default ({ app }, inject) => {
let api = createApiClient();
app.$api = api;
}
Update: Sometimes I got (node:28119) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 2)
I'm sorry, it's my mistake, I had plugins in build. Now it works fine :)
Thank you so much for help! :+1:
I attached my solution:
plugins/dto.js
import { createApiClient } from '@caloriosa/rest-dto'
const TOKEN_KEY = 'access_token' // Put the name of cookie with API token
function getCookie (cookieName, stringCookie) {
let regexCookie = new RegExp('' + cookieName + '[^;]+').exec(stringCookie);
let strCookie = regexCookie ? regexCookie[0] : null
return strCookie ? unescape(strCookie ? strCookie.toString().replace(/^[^=]+./, '') : '') : null
}
export default ({ app, req }, inject) => {
let api = createApiClient();
api.token = getCookie(TOKEN_KEY, req ? req.headers.cookie : document.cookie)
inject('api', api);
}
nuxt.config.js
module.exports = {
loading: { color: '#3B8070' },
build: {
extend (config, ctx) {
if (ctx.dev && ctx.isClient) {
config.module.rules.push({
enforce: 'pre',
test: /\.(js|vue)$/,
loader: 'eslint-loader',
exclude: /(node_modules)/
})
}
}
},
plugins: [ 'plugins/dto' ] // This line injects plugin with DTO client. Must be outside of build node
}
And then we can works with $api in client or serverside:
Page or Vue component
// Server-Side
config.module.rules.push({
enforce: 'pre',
test: /\.(js|vue)$/,
loader: 'eslint-loader',
exclude: /(node_modules)/
})
}
}
},
plugins: [ 'plugins/dto' ] // This line injects plugin with DTO client. Must be outside of build node
}
And then we can works with $api in client or serverside:
Page or Vue component
// Server-Side
asyncData({ app }) {
console.log(app.$api);
app.$api.users.fetchUsers();
},
// Client-Side
mounted() {
console.log(this.$api)
app.$api.users.fetchUsers();
}
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
I attached my solution:
plugins/dto.js
nuxt.config.js
And then we can works with $api in client or serverside:
Page or Vue component
And then we can works with $api in client or serverside:
Page or Vue component