Giter Site home page Giter Site logo

hal-rest-client's People

Contributors

davestewart avatar deblockt avatar dependabot[bot] avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

hal-rest-client's Issues

Model class attributes do not read from props, even when the property is present

After using then on the promise from a fetch with my model class, the returned object's attributes are undefined. The props attribute has all of the correct information, but it doesn't get applied to the model object like it stated in the readme:

Read props is simply call object attributes.
const name = resource.name;

Template links

It seems that library doesn't work with parsing template links. Are you going to implement templates support?

collection under props with undefined objects

Hi again,

I've another case to analyze with you.

This is the json returned by spring application:
https://gist.github.com/baxtheman/0d954791b339647f9044e2e8640a9f96

Inside every commessa master object there is a lavorazioni children objects collection. In the gist you find the java definitions also.

From fetch by the hal-rest-client the resource obtained for a commessa object is this:

Then, why the props.lavorazioni is an not empty array of undefined object?

HalResource's .update() marks all fields as new if list was updated.

Let's get some list to show:
parts: Array<Part>;

If to change parts[0].description and call parts[0].update() - only "description" field is sent to server.
But if we update list: this.provider.loadParts().then(parts => this.parts = parts ); - we will get all fields marked as updated.
Then on parts[0].update() all fields are sent to server.

Could you please separate HalResource certain field update from object replacement? Or some other way to keep list untouched when replace all the list.

get link type

Can we get custom fields like type from link?
For example I have following link:
txt: {href: "projects/path_to_file", type: "text/plain"}

And I want to use "type" for "Accept" header. But I can't get it from the link. I tried something like
file.link("txt").prop("type"), file.link("txt").props , but it doesn't work.

Thanks!

basic auth header not present

Hi,

Talking about version 0.2.6
I need to have authentication and this is the hal client setup:

const options = {
  withCredentials: true,
  auth: {
    username: 'user11',
    password: 'pwd44',
  },
};

const halData = createClient(`${serverUrl}/data`, options);

but no authentication header appears in the first request: https://i.imgur.com/YZfK7oe.png

What's wrong?
thx

reset item can broke some code when the returned object from the server is incomplete

I have tried with 0.5.0 version and everything works fine. Thank you.

But also I've faced another thing:

Fetch parent resource and show it in ui.
Fetch child resouce which has parent as embedded staying on the same ui.
Errors in browser like "Cannot read property 'somename' of undefined" for parent.
As I understand, on fetching child resource parent is reseted. And than created with key-value pairs from new server response. But in embedded object there are less parent properties, than we recieved previously from fetching parent. And as we use parent resource for our ui directly, the problem occure.

Could you suggest something?

building since 0.3.0 broken

Updating from 0.2.0 to 0.3.0 breaks the build process. Neither ng build nor running webpack after a ng eject isn't working anymore. The compiler complains, it cannot find the methods from HalResource, etc. It throws an exception like this:

ERROR in C:/<path>/admin-ui/src/app/app.component.ts (48,46): Property 'link' does not exist on type 'BookingList'.

BookingList is of type HalResource:

export class BookingList extends HalResource {
    @HalProperty(Booking)
    bookings: Booking[] = [];
}

Side note: Navigating in Jetbrains IDE isn't working anymore too.

Is it possible to upload the file during the Resource creation?

Hello,

I'm wondering if it is possible to upload the file during the new Resource creation? e.g:

export class Avatar extends HalResource {

    @HalProperty()
    image: any; // <--- expect to handle the file

    @HalProperty()
    name: string;
}

On the HTML view lets assume we have something like that

<label>UploadAvatar</label>
<input class="form-control" type="file" (change)="onFileInputChange($event)">

TS method looks as below:

onFileInputChange(event) {
        if(event.target.files.length > 0) {
            let file = event.target.files[0];
            const resource = createResource(this.http.halClient, Avatar, "avatar/");
            resource.image = file;
            resource.name = 'Preview';
            resource.create();
        }
}

So this example works and the Ajax call is being made successfully, However the payload is incorrect since image field does not send the File but empty object:
screenshot_1

At the same time if I'll do the same without using hal rest client (via native xhr), the request will be correct! e.g:

onFileInputChange1(event) {
        if(event.target.files.length > 0) {
            let formData = new FormData();
            formData.append('image', event.target.files[0]);
            formData.append('name', 'Preview');
            this.upload.sendFiles(this.http.apiUrl + '/avatar/', formData).subscribe((progress) => {
                console.log(progress);
            }, (error) => {
                console.log(error);
            });
        }
}

Network log:
screenshot_2

Look at original data

Is there any way to look at the original data returned from a request?

I just want to dump this out when getting to know the API so I can see what's what, rather than having to iterate through all embeds.

If I try to dump the instance out JSON.stringify() complains about circular references.

Unless anyone has a better idea of how to do this?

Allow HTTP request/response interceptors setup

Hello,

Recently we have faced with the situation when we need some specific logic that must be called on every HTTP request/response

Interceptors layer will fit our purposes as best.
However Angular2 interceptors won't make any effect since you are using Axios HTTP client for the communications.

However Axios also allows to set up HTTP req/resp interceptors:
https://github.com/mzabriskie/axios#interceptors

Is there any chance to allow interceptors configuring during the HAL REST client setup?
e.g.

this.halClient = createClient(this.apiUrl);
this.halClient.addHeader('Content-Type', 'application/json');
// Add a request interceptor
this.halClient.interceptors.request.use(function (config) {
    // Do something before request is sent
    return config;
  }, function (error) {
    // Do something with request error
    return Promise.reject(error);
});

// Add a response interceptor
this.halClient.interceptors.response.use(function (response) {
    // Do something with response data
    return response;
  }, function (error) {
    // Do something with response error
    return Promise.reject(error);
});

Or similar?

Regards,
Evgeniy

@HalProperty property name alias not working

Problem

I can't seem to alias property names at the same time as setting a model as the documentation says:

I want to:

  • alias the property apps to appsData
  • set the model to be and AppsData instance

Tests

- alias / - model

  @HalProperty()
  public data: AppsData

Can reference data via links but links is a HalResource (I know this is because links are raw):

image

+ alias / - model

  @HalProperty('apps')
  public appsData: AppsData

Can reference data by appsData but property is a HalResource:

image

- alias / + model

  @HalProperty(AppsData)
  public apps: AppsData

Can only reference data by apps and property is an AppsData model

image

+ alias / + model

  @HalProperty('apps', AppsData)
  public appsData: AppsData

Can reference data by apps but property is not an AppsData model

image

Question

This last setup should have aliased apps to appsData and appsData should have been an AppsData model, no?

Templated link parameters are not stored for later reuse (fetchedURI always empty?)

Short

When I query a resource with a templated link like /api/resource/{id} the value for id isn't stored in the resource.

Long

I have this rels-object that functions as dictionary for all my endpoints in the API:

{
    "_links": {
        "self": {
            "href": "/api/v1/rels.hal"
        },
        "calculation": {
            "href": "/api/v1/calculation/{id}",
            "templated": true
        },
        "customer": {
            "href": "/api/v1/customer/{id}",
            "templated": true
        }
    }
}`

In my application I fetch a calculation resource like (rels is of type HalResource)

let calculation = rels.links('calculation').fetch({id: 5})

Which works fine. But when I want to update the resource calculation.update() the templated URL isn't resolved with the initial attributes {id: 5}.

After looking through the source code I found the member URI:fetchedURI, but it seems that the value is always empty. Shouldn't it be filled with the resolved URL of the fetched Resource?

Link caching

Do Links get cached? If yes, why? I would like to show stuff based on if the Link is missing or shown. Is this possible?

resource.create() in version 0.3.0 differs from 0.2.6

Hi,

I've upgrade to last version 0.3.0 and the resource.create() gets error from the java spring data backend.

Code to save new resource:

const resource = createResource(halData, HalResource, '/rilevazione');

resource.prop('data', date);
resource.prop('commessa', order.links.commessa.uri);

resource.create()

the json POST by browser to backend, version 0.2.6

{
    "commessa": "http://95.242.194.83:8080/test-api-v3/data/commessa/1641",
    "data": "2017-10-02T22:00:00.000Z",
    ...
}

the json POST by browser to backend, version 0.3.0

{
	"commessa": {
		"fetchedURI": "",
		"templated": false,
		"uri": "http://localhost:8180/registrazioni/data/commessa/1630"
	},
	"data": "2017-10-02T22:00:00.000Z",
	...
}

The last version is not recognized by the backend and it produces an exception (commessa field empty).

What can I do to resolve?
thx

Fetch method does not cast resource to an appropriate type

Hi Thomas,

I've faced with a strange issue:
In my code I retrieve dashboard data as like below:

async loadDashboardData(): Promise<DashboardInfo> {
     return await this.http.halClient.fetch("/dashboard", DashboardInfo);
}

So according to the documentation I expect to retrieve instance of DashboardInfo type as a result.

However, instead i get an object of base HalResource type:
untitled

In all other cases casting went well. So after some research I've found out interesting thing:

If during the previous requests to API through the halClient I will get a HAL resource with a link to the same href equal "/dashboard", then future casting won't work anymore.

It seems like halClient automatically cast all the Links to the default base HalResource type, which makes impossible future casting through the fetch method as in example above.

Can you please take a look on that?

P.S. In support of my idea - once I remove the "/dashboard" href from my API responces, code above has started to work fine and output DashboardInfo instance instead of HalResource.

Best Regards,
Evgeniy

Fetching from a link isn't working (in Angular?)

There is this setup:

export class CustomerResource extends HalResource {
    @HalProperty()
    id: number
    @HalProperty()
    name: string
    // @HalProperty(StoreResource)
    // stores: Array<Store>
}

@Injectable()
export class CustomerService {

    getCustomers(): Promise<CustomerResource[]> {
        const uri = this.createUrl('customer')
        return this.client.fetchArray(uri, CustomerResource)
    }

    getStores(customer: CustomerResource): Promise<StoreResource[]> {
        const resource = customer.link('stores')
        const link = resource.fetch()
        return (<Promise<any>>link)
    }    
}

When I call customerService.getStores(customer) I get the error Error: object is not hal resource [<array of stores>]. It doesn't change a thing if I comment out the stores field in the CustomerResource type or not. However, fetching the customer in the first place works fine. And I don't see any difference to your example code (besides the await statements) in the wiki.

There is a alternate approach that actually works, but I guess it wasn't meant to be (looks a bit ugly to me ;)

const link = customer.link('stores').uri.uri
return this.client.fetchArray(link, StoreResource)

As you may already have guessed by the @Injectable() decorator, I'm using Angular 5 and calling resource.fetch() returns a ZoneAwarePromise. Maybe that's a clue.

Link override props

Hi!
We are trying to use your library but step into the issue.
If we have prop in json and have link with similar name

{
  "_links": {
    "parent": { "href": "..."  }
  },
  "title": "Test category",
  "parent": "Test parent"
}

When we parse it:
resource.props.parent - undefined
resource.prop('parent') - returns HalResource, but we're expecting to get "Test parent" here

I check your code and find condition that is responsible for this bug

Also if you look closer to the parser, it's obviously have a racing issue and result depends on the json key order
When you iterating over the json the key order is not determinated

for (const key in json) {
  ...
}

So in case your json has "_links" key before other props – you get one result
If key order is different you will get another result (Your if-condition will go to the "else", because _links field will be parsed after "parent" :

{
  "title": "Test category",
  "parent": "Test parent",
  "_links": {
    "parent": { "href": "..."  }
  }
}

Models not always loading and / or populating

I gotta say, I'm loving HalResource models and @HalProperty decorators! Amazing stuff, well done.

However, I've found model population and loading to be a big hit and miss, I assume, because of 1) my coding but possibly 2) the data.

I had a hierarchy loading well, but it now seems to have stopped loading at appData (I am aliasing this in the model decorator):

export default class Company extends HalResource {
  @HalProperty()
  public name: string

  @HalProperty('apps', AppsData)
  public appsData: AppsData
}
sites.sites[0].companies[0].links.appsData.isLoaded // false

image

The JSON / class mapping is:

- Sites
  - _link: sites[]
    - Site
      - _embed: companies[]
        - Company
          - _link: appsData (originally apps)
            - AppsData
              - _embed: apps[]
                - App

The site data is:

{
  "name": "DEV",
  "_embedded": {
    "companies": [
      {
        "name": "Space Invaders Parent - DEV",
        "_links": {
          "self": {
            "href": "https://spaceinvaders.bookingbug.com/api/v1/site/37003"
          },
          "install_app": {
            "href": "https://spaceinvaders.bookingbug.com/api/v1/37003/apps/install_from_portal{?name}",
            "templated": true
          },
          "apps": {
            "href": "https://spaceinvaders.bookingbug.com/api/v1/site/apps"
          }
        }
      }
    ]
  },
  "_links": {
    "self": {
      "href": "https://spaceinvaders.bookingbug.com/api/v1/site"
    }
  }
}

The link site > _embed:companies[] > _link:apps is supposed to load:

{
  "total_entries": 1,
  "_embedded": {
    "apps": [
      {
        "id": 2,
        "name": "vidyo",
        ...
      }
    ]
  },
  "_links": {
    "self": {
      "href": "https://spaceinvaders.bookingbug.com/api/v1/admin//apps"
    }
  }
}

I assume I need a model class for every link and every embed?

It seems that if I match the data hierarchy wrong, a model will be instantiated but with everything undefined.

I'm pretty sure at some point I had the Apps loading.

My hunch is that the lib is getting confused as there are two consecutive apps keys.

Is there any way to debug a model as it populates?

Cannot parse link as resource if mapping link name from hal through @HalProperty() decorator

Lets say I have a model which has a field expected as link.

Model:

export class Foo extends HalResource {
   @HalProperty('response.bar')
   bar: Bar; // it's link
}

When fetching Foo resource hal-parser spits out bar field as HalResorce not as Bar which is incorrect behavior. After some debugging I found that library passes to method Reflect.getMetadata link key as it is from hal json (e.g. 'response.bar') but MetadataMap contains field names and appropriate constructors in format that is specified in @HalProperty() decorator (e.g. 'bar'). Apparently proper constructor cannot be found by incorrect key and that leads to casting Bar field to HalResource.

Fetch Generic model data?

Hi Thomas,

One of my API endpoints returns me a set of similar structures which i'd like to map on my custom client side HAL resource model.

The output structure is looks like below:

data:
     set1:
           count: 3
           list: [type1, type1, type1]
     set2:
           count: 2
           list: [type2, type2]
     set3:
           count: 4
           list: [type3, type3, type3, type3]

So, I've tried to to map such a structure on the following kind of model:

class InfoSet<T extends HalResource> extends HalResource {
    @HalProperty()
    count: number;

    @HalProperty(T) <---- ERROR: 'T' only refers to a type, but is being used as a value here
    list: T[];
}

export class Data extends HalResource {
    @HalProperty(InfoSet)
    set1: InfoSet<Type1>;

    @HalProperty(InfoSet)
    set2: InfoSet<Type2>;

    @HalProperty(InfoSet)
    set3: InfoSet<Type3>;
}

But it shows an error as displayed above at 5th row

So I've tried to workaround that as like that:

class InfoSet<T extends HalResource> extends HalResource {
    test: T;

    @HalProperty()
    count: number;

    @HalProperty(typeof this.test) <--- No more error
    list: T[];
}

After that there were no any compile time issues anymore, but on application open , i've got the next error in browser console:
image

Where DashboardInfo is the same InfoSet but in my real app.

But T already extends HalResource type..

Is it possible to map response data on typescript generic HAL models?
If yes, what am i doing wrong?

Regards,
Evgeniy

Allow CORS requests with credentials

Hello,

Is there any chance to allow CORS requests sending using the credentials?

In XHR there is a field called withCredentials that allows that:
https://developer.mozilla.org/ru/docs/Web/API/XMLHttpRequest/withCredentials

I guess you are using the Axios HTTP client which supports this config setup:
https://github.com/mzabriskie/axios#request-config

Is there any chance to allow withCredentials config during HAL REST client setup?
e.g.

this.halClient = createClient(this.apiUrl);
this.halClient.addHeader('Content-Type', 'application/json');
this.halClient.withCredentials = true; // SOMETHING LIKE THAT

Regards,
Evgeniy

Bug from upgrade 0.4.1 -> 0.5.0

Backend is sending a response

embedded: {
signal: {
mysignal: "test"
}
},
links: {
signal: "http://mysignal.de"
}

Hal-Rest-Client is converting it:
links: signal does exist
props.signal: signal is undefined

  • this is the most likely reason for that bug. There might be another issue. In version 4.1.0 we do see the property while its missing in >4.1.0
    The bug to be solved is: An embedded property does not show up in .props

error parsing json

Please, see this hal json response from Spring Data application:

https://gist.github.com/baxtheman/5873c9de7821970f2d075b733ee6a3c4

It causes a parsing error calling the service with fetchResource

Uncaught (in promise) TypeError: Cannot read property 'href' of undefined at JSONParser.jsonToResource (19:17) at JSONParser.parseJson (19:67) at eval (19:63) at Array.map (<anonymous>) at JSONParser.parseJson (19:63) at JSONParser.jsonToResource (19:45) at JSONParser.parseJson (19:67) at eval (19:63) at Array.map (<anonymous>) at JSONParser.parseJson (19:63)

This the position of the exception:

Any suggestions?
thx

Make restClient protected

It would be useful to make HalResource.restClient field protected instead of private. This allows to create additional method in model classes that will make some requests or use the base url. For example, request for images or other non-HAL resources.

Are arrays of links supported?

If I have the following JSON, it seems that arrays of links cannot be fetched:

{
  "_links": {
    "self": {
      "href": "https://example.com/sites"
    },
    "site":  { "href": "https://example.com/sites/1" },
    "sites": [
      { "href": "https://example.com/sites/1" },
      { "href": "https://example.com/sites/2" },
      { "href": "https://example.com/sites/3" }
    ]
  }
}

Site:

sites.link('site').fetch().then(console.log)
HalResource {_uri: URI, links: {…}, props: {…}, isLoaded: true, settedProps: Array(0), …}

Sites:

sites.link('sites').fetch().then(console.log)
Promise {<rejected>: TypeError: Cannot read property 'replace' of undefined
    at combineURLs (webpack-internal:///./nod…}
combineURLs.js?2053:11 Uncaught (in promise) TypeError: Cannot read property 'replace' of undefined
    at combineURLs (combineURLs.js?2053:11)
    at Axios.request (Axios.js?951a:41)
    at Axios.(anonymous function) [as get] (webpack-internal:///./node_modules/hal-rest-client/node_modules/axios/lib/core/Axios.js:67:17)
    at Function.wrap [as get] (bind.js?ff72:9)
    at eval (hal-rest-client.js?ab6a:82)
    at new Promise (<anonymous>)
    at HalRestClient.fetch (hal-rest-client.js?ab6a:81)
    at HalResource.fetch (hal-resource.js?dd8c:32)
    at <anonymous>:2:21

The spec says this should be possible (see ea:order):

We are using another HAL library as well, and it handles arrays of links just fine.

HalCollection

It seems that fetching collections of links could do with a bit of sugar.

Right now, to collect a list of resources from an array of links we need something along the lines of:

function fetch (res, name) {
  const target = res.prop(name)
  return Array.isArray(target)
    ? Promise.all(target.map(t => t.fetch()))
    : target.fetch()
}

If we had a HalCollection class, with perhaps an IFetchable interface, both HalResource and HalCollection could be fetch()ed:

const results = res.prop('site').fetch().then( /* Site or Array of Sites */ )

Of course the collection class would be iterable just like an Array as well.

What do you think?

Force data updating using HalRestClient fetchArray

Hello,

It would be useful to add possibility to force data updating when using HalRestClient fetchArray method. (Currently there is a force param in HalResouce fetch method that do the trick.)

I've faced with an issue related to this updating. When I retrieve data using HalRestClient fetchArray method, I expect to see new response each time, but instead I recieve partly updated one with cached properties from previous call.

Resource Variables override each other

If i create multiple "sub-requests" out of the same main Request, those sub request seem to override each others properties.

this.mainRequest = await getResponseFromEntryPoint('/')
this.resource1 = await this.mainRequest.link('byKey').fetch({key: 'keyVal1'})
this.resource2 = await this.mainRequest.link('byKey').fetch({key: 'keyVal2'})
this.resource3 = await this.mainRequest.link('byKey').fetch({key: 'keyVal3'})

These resource variables override each other. Therefore the edit link on all those resources is the same, the one of the last request.

Is this a bug or am I just using the hal-rest-client wrong?

Handling paging info

Hello. Any idea how to handle paging information when fetching an array? I mean:
{
"_embedded": {
"products": [ { ... } ]
},
"_links": { ... },
"page": {
"size": 20,
"totalElements": 100,
"totalPages": 5,
"number": 0
}

}

I figured out a workaround for that, but it requires 2 requests (one for fetching an array, one for page info).
Can we do it in one shot?

Thanks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.