-
Notifications
You must be signed in to change notification settings - Fork 7
Open
Labels
Description
Used libraries
core, jsonapi, jsonapi-angular, utils
Library version(s)
"@datx/core": "^3.0.0", "@datx/jsonapi": "^3.0.0", "@datx/jsonapi-angular": "^3.0.0", "@datx/jsonapi-types": "^3.0.0", "@datx/network": "^3.0.0", "@datx/utils": "^3.0.0",
Issue description
When retrieving the model via a custom url the data is not being set inside the object.
Whereas I retrieve all the users after, the data is getting filled properly.
Response from api
{
"jsonapi":{
"version":"1.0"
},
"links":{
"self":"http:\/\/localhost\/api\/v1\/users\/1"
},
"data":{
"type":"users",
"id":"1",
"attributes":{
"name":"Stefan Willems",
"email":"",
"given_name":"Stefan",
"family_name":"Willems",
"created_at":"2023-09-25T10:04:06.000000Z",
"updated_at":"2023-09-25T10:04:06.000000Z"
},
"relationships":{
"roles":{
"links":{
"related":"http:\/\/localhost\/api\/v1\/users\/1\/roles",
"self":"http:\/\/localhost\/api\/v1\/users\/1\/relationships\/roles"
},
"data":[
{
"type":"roles",
"id":"2"
}
]
},
"revisions":{
"links":{
"related":"http:\/\/localhost\/api\/v1\/users\/1\/revisions",
"self":"http:\/\/localhost\/api\/v1\/users\/1\/relationships\/revisions"
},
"data":[
]
}
},
"links":{
"self":"http:\/\/localhost\/api\/v1\/users\/1"
}
},
"included":[
{
"type":"roles",
"id":"2",
"attributes":{
"name":"user"
},
"relationships":{
"permissions":{
"links":{
"related":"http:\/\/localhost\/api\/v1\/roles\/2\/permissions",
"self":"http:\/\/localhost\/api\/v1\/roles\/2\/relationships\/permissions"
},
"data":[
{
"type":"permissions",
"id":"1"
},
{
"type":"permissions",
"id":"10"
},
{
"type":"permissions",
"id":"11"
},
{
"type":"permissions",
"id":"12"
},
{
"type":"permissions",
"id":"13"
},
{
"type":"permissions",
"id":"14"
}
]
}
},
"links":{
"self":"http:\/\/localhost\/api\/v1\/roles\/2"
}
},
{
"type":"permissions",
"id":"1",
"attributes":{
"name":"login-permission"
},
"links":{
"self":"http:\/\/localhost\/api\/v1\/permissions\/1"
}
},
{
"type":"permissions",
"id":"10",
"attributes":{
"name":"file-read"
},
"links":{
"self":"http:\/\/localhost\/api\/v1\/permissions\/10"
}
},
{
"type":"permissions",
"id":"11",
"attributes":{
"name":"file-create"
},
"links":{
"self":"http:\/\/localhost\/api\/v1\/permissions\/11"
}
},
{
"type":"permissions",
"id":"12",
"attributes":{
"name":"file-delete"
},
"links":{
"self":"http:\/\/localhost\/api\/v1\/permissions\/12"
}
},
{
"type":"permissions",
"id":"13",
"attributes":{
"name":"file-upload"
},
"links":{
"self":"http:\/\/localhost\/api\/v1\/permissions\/13"
}
},
{
"type":"permissions",
"id":"14",
"attributes":{
"name":"file-update"
},
"links":{
"self":"http:\/\/localhost\/api\/v1\/permissions\/14"
}
}
]
}Object inside Angular
{
"__META__": {
"type": "users",
"id": "1",
"fields": {
"name": {
"referenceDef": false
},
"email": {
"referenceDef": false
},
"given_name": {
"referenceDef": false
},
"family_name": {
"referenceDef": false
},
"company": {
"referenceDef": {
"type": 0,
"model": "companies"
}
},
"roles": {
"referenceDef": {
"type": 1,
"model": "roles"
}
},
"revisions": {
"referenceDef": {
"type": 1,
"model": "revisions"
}
},
"created_at": {
"referenceDef": false
},
"updated_at": {
"referenceDef": false
}
},
"jsonapiLinks": {
"self": "http://localhost/api/v1/users/1"
},
"networkPersisted": true,
"jsonapiRefLinks": {
"roles": {
"related": "http://localhost/api/v1/users/1/roles",
"self": "http://localhost/api/v1/users/1/relationships/roles"
},
"revisions": {
"related": "http://localhost/api/v1/users/1/revisions",
"self": "http://localhost/api/v1/users/1/relationships/revisions"
}
},
"jsonapiRefMeta": {}
},
"company": null,
"roles": [
{
"id": "2",
"type": "roles"
}
],
"revisions": [],
"created_at": "2023-09-25T10:04:06.000000Z",
"updated_at": "2023-09-25T10:04:06.000000Z"
}Request being send from client
public me(include?: string): Observable<User> {
const options: IRequestOptions = {} as IRequestOptions;
options.queryParams = {};
if (include) {
options.queryParams.include = include;
}
return this.collection.request('users/me', HttpMethod.Get, null, options).pipe(map((response: Response) => {
console.log(response.data);
return response.data;
}));
}App module
import {BrowserModule} from '@angular/platform-browser';
import {APP_INITIALIZER, ErrorHandler, NgModule} from '@angular/core';
import {AppRoutingModule} from './app-routing.module';
import {AppComponent} from './app.component';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {HTTP_INTERCEPTORS, HttpClient, HttpClientModule} from '@angular/common/http';
import {VersionMismatchInterceptor} from './interceptors/version-mismatch.interceptor';
import {NoConnectionInterceptor} from './interceptors/no-connection.interceptor';
import {DashboardModule} from './dashboard/dashboard.module';
import {MainModule} from './main/main.module';
import {MaterialModule} from './material/material.module';
import * as Sentry from '@sentry/angular-ivy';
import {APP_COLLECTION, DATX_CONFIG, setupDatx} from '@datx/jsonapi-angular';
import {AppCollection} from './collections/app.collection';
import {AuthenticationModule} from './authentication/authentication.module';
import {UnauthorizedInterceptor} from './interceptors/unauthorized.interceptor';
import {CustomFetchService} from './services/custom-fetch.service';
import {CachingStrategy} from '@datx/network';
import {config} from '@datx/jsonapi';
function initDatx(customFetch: CustomFetchService): () => Promise<void> {
return async () => {
config.baseFetch = customFetch.fetch.bind(customFetch);
config.defaultFetchOptions = {
credentials: 'same-origin',
headers: {
'Content-Type': 'application/vnd.api+json',
},
};
// Use cache if not older than 10 seconds
config.maxCacheAge = 10;
config.cache = CachingStrategy.CacheFirst;
};
}
@NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule,
AuthenticationModule,
AppRoutingModule,
BrowserAnimationsModule,
DashboardModule,
MainModule,
MaterialModule,
HttpClientModule,
],
providers: [
{provide: HTTP_INTERCEPTORS, useClass: NoConnectionInterceptor, multi: true},
{provide: HTTP_INTERCEPTORS, useClass: VersionMismatchInterceptor, multi: true},
{provide: HTTP_INTERCEPTORS, useClass: UnauthorizedInterceptor, multi: true},
{
provide: ErrorHandler,
useValue: Sentry.createErrorHandler({
showDialog: false,
}),
},
{provide: APP_COLLECTION, useValue: new AppCollection()},
{
provide: DATX_CONFIG,
useFactory: (httpClient: HttpClient) => {
return setupDatx(httpClient, {
baseUrl: '/api/v1/',
});
},
deps: [HttpClient],
},
{
provide: APP_INITIALIZER,
useFactory: initDatx,
multi: true,
deps: [CustomFetchService],
},
],
bootstrap: [AppComponent]
})
export class AppModule {
}Custom Fetch Service
import {HttpClient} from '@angular/common/http';
import {Injectable} from '@angular/core';
import {config, IResponseObject} from '@datx/jsonapi';
import {lastValueFrom, Observable} from 'rxjs';
import {map, takeUntil} from 'rxjs/operators';
import {IResponseHeaders} from '@datx/utils';
@Injectable({providedIn: 'root'})
export class CustomFetchService {
constructor(private httpClient: HttpClient) {
}
public async fetch(
method: string,
url: string,
body?: unknown,
headers: Record<string, string> = {},
fetchOptions?: { takeUntil$?: Observable<void> },
): Promise<IResponseObject> {
const takeUntil$: Observable<void> | undefined = fetchOptions?.takeUntil$;
const requestHeaders = {
...config.defaultFetchOptions.headers,
...headers,
};
let request$ = this.httpClient
.request(method, url, {
observe: 'response',
responseType: 'json',
headers: requestHeaders,
body,
})
.pipe(
map((response) => {
return {
data: response.body,
headers: response.headers as unknown as IResponseHeaders, // The interface actually matches
requestHeaders,
status: response.status,
};
}),
);
if (takeUntil$) {
request$ = request$.pipe(takeUntil(takeUntil$));
}
try {
const d = await lastValueFrom(request$);
if (d === undefined) {
return {status: -1}; // Signal to DatX that it shouldn't fail, but shouldn't cache either
}
return d;
} catch (e) {
console.error(e);
throw e;
}
}
}