gizm0bill / angular2-rest-client

MIT License
8 stars 5 forks source link

Extend interface to include the type of the response #9

Open michaelwiles opened 6 years ago

michaelwiles commented 6 years ago

This is a feature request.

I'm wondering if it's possible to do something like:

@Injectable()
@BaseUrl('http://localhost:8080/rest/service')
export class ManagerService extends AbstractApiClient {

  constructor(protected http: Http) { super(http); }

  @Type(ResponseContentType.Json)
  @GET('/batch')
  public batches(  ): Observable<TypedResponse<Batch[]> { return; }
}

I would assume that TypedResponse would extend the current response.

With current solution all I need to do is cast the json response to that Batch[]...

const response: Observable<Response> = this.service.batches();
    response.subscribe(item => {
      const b = item.json() as Batch[];
      console.log(b[0].startTime);
    });

It would just be a lot more convenient if this was done inside. Not sure if this is possible of course.

I'm a serious newby with js and ts and have tried to have a look at where this could be put but have no clue where to start...

gizm0bill commented 6 years ago

Can't you already do that? there is a @Type decorator defined. The spec for it is here (but it's tested with a blob): https://github.com/gizm0bill/angular2-rest-client/blob/master/tests/angular2-rest-client.spec.ts#L359

michaelwiles commented 6 years ago

The @Type decorator is of type ResponseContentType

It is not used for specifying the narrow type of the response. But how you want the response treated.

To support my idea you would probably need to have this type set to Json because that is the one that can be typed.

gizm0bill commented 6 years ago

Hmmm.. I see what you mean, it could be done but until I get the time to implement it maybe you could just make yourself a rxjs operator, following the example here https://netbasal.com/create-the-tojson-operator-in-angular-adaac9356e21 But keep in mind that what you are trying to do here: item.json() as Batch[] doesn't actually produce real Batch array, i.e b[0] instanceof Batch would evaluate to false, since these casts are removed after the build. So you could implement yourself an operator something like toTypedJSON and toTypedJSONArray, basically something in the lines of this:

function toTypedJSON<T>( classRef: new() => T ): Observable<T> {
  return this.map( ( res: Response ) => Object.assign( new classRef, res.json() ) )
}

function toTypedJSONArray<T>( classRef: new() => T ): Observable<T[]> {
  return this.map( ( res: Response ) => res.json().map( item => Object.assign( new classRef, item ) ) )
}
...
this.service.batches().toTypedJSONArray(Batch)
michaelwiles commented 6 years ago

Thanks a lot.

I'm very new to typescript/javascript so that is some new ideas for me.

Though I'm not concerned about making sure instanceOf works. My Batch type is an interface in any case so AFAIK even with this funky stuff it won't be in the javascript.