Hot to add POST interceptor to aurelia http client - aurelia

Basically, the question says it all :). The scenario is as follows: I have some python models that are being passed between the browser, and the server. Python convention for naming things is to use underscores, and js convention is to camelCase everything. So I figured, I'd just create an http request interceptor to convert between python_models and jsModels. Is there a simple way to accomplish that?
I'm also looking for a way to do the inverse, so camelCase to that-case :)

If you're using aurelia-http-client, you can use a reviver.
import {HttpClient} from 'aurelia-http-client';
import {Person} from './models';
export class PersonService {
constructor(){
this.http = new HttpClient().configure(x=> {
x.withReviver((k,v) => {
return typeof v === 'object' ? new Person(v) : v;
});
});
}
getPeople(){
return this.http.get('/people');
}
}
This only works for aurelia-http-client and not aurelia-fetch-client. It has been talked about in the fetch spec, but I don't believe it is currently implemented.
Check the following for more information:
(my) Best Practices in Aurelia: The Model
https://github.com/whatwg/fetch/issues/104

Related

How to use TypeGraphQL with tsyringe

I have a project using tsyringe and a RESTFul API. Now i should to add a GraphQL API using the type-graphql but in our documentation no have some example using it.
Is possiblem to use tsyringe to make DI with TypeGraphQL?
Yes, it's possible!
Most IOC containers have the get function to retrieve an instance of the given class type. tsyringe instead have the resolve function.
Therefore, you have to change the container option when building the schema to instruct type-graphql how to retrieve (get) a class instance from a class type:
import { container } from 'tsyringe';
const schema = await buildSchema({
// ...
container: { get: (cls) => container.resolve(cls) }
});

An updated approach to testing vuex actions

In the "Testing Actions" documentation, there is a recommendation to use inject-loader in order to mock entire module imports, and their respective dependencies, when unit testing.
For example, you can mock the ../api/shop import found inside the ./actions file with the following:
const actionsInjector = require('inject-loader!./actions')
// create the module with our mocks
const actions = actionsInjector({
'../api/shop': {
getProducts (cb) {
setTimeout(() => {
cb([ /* mocked response */ ])
}, 100)
}
}
})
Unfortunately, that package does not support Webpack 5.
Is there an updated approach, or alternative package, that is recommended?
Thanks #Estus Flask.
The clarification/mixup was that, whilst I was using vi.mock, and it's auto-mocking algorithm :
"...will mock the module itself by invoking it and mocking every
export."
i.e. it still runs the import statements. To prevent this, a factory must be provided (see documentation), e.g.:
vi.mock('module', <factory-here>)
Which then replaces the entire file import.

Nuxt class-based services architecture (register globally; vs manual import)

In my Nuxt app I'm registering app services in a plugin file (e.g. /plugins/services.js) like this...
import FeatureOneService from '#/services/feature-one-service.js'
import FeatureTwoService from '#/services/feature-two-service.js'
import FeatureThreeService from '#/services/feature-three-service.js'
import FeatureFourService from '#/services/feature-four-service.js'
import FeatureFiveService from '#/services/feature-five-service.js'
export default (ctx, inject) => {
inject('feature1', new FeatureOneService(ctx))
inject('feature2', new FeatureTwoService(ctx))
inject('feature3', new FeatureThreeService(ctx))
inject('feature4', new FeatureFourService(ctx))
inject('feature5', new FeatureFiveService(ctx))
}
After doing this I can access any of my service on vue instance like this.$feature1.someMethod()
It works but I've once concern, that is, this approach loads all services globally. So whatever page the user visits all these services must be loaded.
Now I've 20+ such services in my app and this does not seem optimal approach to me.
The other approach I was wondering is to export a singleton instance within each service class and import this class instance in any component which needs that service.
So basically in my service class (e.g. feature-one-service.js) I would do like to do it like this..
export default new FeatureOneService() <---- I'm not sure how to pass nuxt instance in a .js file?
and import it my component where it is required like so...
import FeatureOneService from '#/services/feature-one-service.js'
What approach do you think is most feasible? if its the second one, then how to pass nuxt instance to my singleton class?
Yep, loading everything globally is not optimal in terms of performance.
You will need to either try to use JS files and pass down the Vue instance there.
Or use mixins, this is not optimal but it is pretty much the only solution in terms of reusability with Vue2.
Vue3 (composition API) brings composables, which is a far better approach regarding reusability (thing React hooks).
I've been struggling a lot with it and the only solution is probably to inject services to the global Vue instance at the component/page level during the initialisation (in created hook), another option is to do that in the middleware (or anywhere else where you have access to the nuxt context. Otherwise you won't be able to pass nuxt context to the service.
I usually set up services as classes, call them where necessary, and pass in the properties of the context which the class depends on as constructor arguments.
So for example, a basic MeiliSearchService class might look like:
export class MeilisearchService {
#client: MeiliSearch
constructor($config: NuxtRuntimeConfig) {
super()
this.#client = new MeiliSearch({
host: $config.services.meilisearch.host,
apiKey: $config.services.meilisearch.key
})
}
...
someMethod() {
let doSomething = this.#client.method()
...
}
...
}
Then wherever you need to use the service, just new up an instance (passing in whatever it needs) and make it available to the component.
data() {
const meiliSearchService = new MeiliSearchService(this.$config)
return {
meiliSearchService,
results,
...
}
},
methods: {
search(query) {
...
this.results = this.meiliSearchService.search(query)
...
}
}
As I'm sure you know, some context properties are only available in certain Nuxt life-cycle hooks. I find most of what I need is available everywhere, including $config, store, $route, $router etc.
Don't forget about Vue's reactivity when using this approach. For example, using a getter method on your service class will return the most recent value only when explicitly called. You can't, for example, stick the getter method in a computed() property and expect reactivty.
<div v-for='result in latestSearchResults'>
...
</div>
...
computed: {
latestSearchResults() {
return this.#client.getLatestResults()
}
}
Instead, call the method like:
methods: {
getLatestResults() {
return this.#client.getLatestResults()
}
}

Aurelia support for XML

Will support be provided for XML file reads/writes? If I read the Aurelia docs correctly, Aurelia-fetch-client and aurelia-http-client, are configured for/expecting JSON response types (HTTP Services in Aurelia docs). I have a very large SPA conversion project and want to use Aurelia. However, all the page content and pointers are output in an XML document and mapped via GUIDs. Do I need to build a custom routine for XML to JSON for use with Aurelia?
The Fetch API specification currently doesn't have any methods to take/ convert the response stream as XML Document (https://developer.mozilla.org/en-US/docs/Web/API/Response#Methods). (The same fetch API is used by Aurelia if the browser supports it or it uses a polyfill (whatwg fetch) that implements matching logic to the API)
What you can do is get the stream as text and then parse the output with a library that can parse XML.
For example with jQuery's parseXML (https://api.jquery.com/jQuery.parseXML/) method:
import {autoinject} from 'aurelia-framework';
import {HttpClient} from 'aurelia-fetch-client';
import 'fetch';
import * as $ from 'jquery';
#autoinject
export class XMLFetchTest {
constructor(private http: HttpClient) {
http.configure(config => {
config
.useStandardConfiguration()
.withBaseUrl('/src/');
});
}
public activate() {
return this.http.fetch('test.xml')
.then(response => response.text())
.then(text => {
let doc = $.parseXML(text);
}));
}
}

Babel/ES6 extended class methods undefined

Currently I'm using Babel to write a Node.js backend in ES6. Unfortunately I encountered a strange behaviour when extending a specific class. Some of my methods, defined in the extending class, are undefined. Unless I use the ES7 syntax to bind them to a property.
This is the actual code that gives me this strange behaviour:
import { Router } from 'express';
class MyCustomRouter extends Router
{
constructor() {
super();
this.methodWorks(); // works like a charm.
this.methodDoesnt(); // throws TypeError: _this.methodDoesnt is not a function
}
methodWorks = () => {
// some content
}
methodDoesnt() {
// some content
}
}
This is actually extends the Router from the expressjs library. So right now I'm just curious if someone could explain this behaviour and/or if there is a way to fix this.
I went looking inside the code of ExpressJS itself to find some explanation. Apparently they like to return a whole new and different context from the Router's constructor. Which explains why this is totally different and not containing my methods...