Skip to content

[Typescript][Angular]Issue #6902 Return Client Response for Angular 4.3 and above with Observe string#6955

Merged
wing328 merged 4 commits intoswagger-api:masterfrom
kenisteward:returnClientResponse
Nov 23, 2017
Merged

[Typescript][Angular]Issue #6902 Return Client Response for Angular 4.3 and above with Observe string#6955
wing328 merged 4 commits intoswagger-api:masterfrom
kenisteward:returnClientResponse

Conversation

@kenisteward
Copy link
Copy Markdown
Contributor

@kenisteward kenisteward commented Nov 14, 2017

PR checklist

  • Read the contribution guidelines.
  • Ran the shell script under ./bin/ to update Petstore sample so that CIs can verify the change. (For instance, only need to run ./bin/{LANG}-petstore.sh and ./bin/security/{LANG}-petstore.sh if updating the {LANG} (e.g. php, ruby, python, etc) code generator or {LANG} client's mustache templates). Windows batch files can be found in .\bin\windows\.
  • Filed the PR against the correct branch: 3.0.0 branch for changes related to OpenAPI spec 3.0. Default: master.
  • Copied the technical committee to review the pull request if your PR is targeting a particular programming language.

Description of the PR

Fixes #6902 with some added bonuses
@bedag-moo @HermenOtter Gonna need you 2 to test this as i'm not currently running angular ^4.3 Will be upgrading to 5 very soon though.

Note: For overloads to work with proper intellisense the first overload must always be for 'body'. if any changes are made to the overload that rearranges them intellisense will break and confuse consumers

Techies!

@TiFu @taxpon @sebastianhaas @Vrolijkx

let requestOptions: RequestOptionsArgs = new RequestOptions({
method: RequestMethod.Get,
headers: headers,
headers,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest not to remove the explicit headers: part, since without it, refactoring variable names can easily lead to problems

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not exactly sure hat you mean. Please elaborate so i can understand. Thanks!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kenisteward when creating objects like this:

{
    something
}

instead of

{
    something: something
}

the name of the property of the object changes when refactoring variable names, leading to potential problems if one does not notice it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh. Unfortunately, mostly due to how our templates are setup, that will be a big breaking change either way.

For the 4.3 client and the non 4.3 client they both use the same name for a variable however if someone changed the name for 1 client thinking it would be fine that would also cause errors.

I'm also assuming you mean refactoring via our mustache templates as one should not be refactoring their code directly as new versions should be automatically generated.

@HermenOtter
Copy link
Copy Markdown

HermenOtter commented Nov 14, 2017

@kenisteward When generating with Angular typescript 4.3, typescript returns this error:

severity: 'Error'
message: Argument of type '{ params: HttpParams; withCredentials: boolean; headers: HttpHeaders; observe: "body" | "response...' is not assignable to parameter of type '{ headers?: HttpHeaders; observe?: "body"; params?: HttpParams; reportProgress?: boolean; respons...'.
  Types of property 'observe' are incompatible.
    Type '"body" | "response" | "events"' is not assignable to type '"body"'.
      Type '"response"' is not assignable to type '"body"'.
source: 'ts'

All my httpClient actions have this problem, but as example this snippet:

return this.httpClient.get<InlineResponse200>(`${this.basePath}/subj/v1/subjecten/`,
            {
                params: queryParameters,
                withCredentials: this.configuration.withCredentials,
                headers,
                observe,
                reportProgress
            }
        );

@HermenOtter
Copy link
Copy Markdown

HermenOtter commented Nov 14, 2017

@kenisteward Could it have something to do with the order of elements in the options object? It might be the intellisense in vscode messed up.

@kenisteward
Copy link
Copy Markdown
Contributor Author

@HermenOtter turns out i missed up the mustache template for when there are no previous fileds but we still need observe / report progress looking into this now.

@HermenOtter
Copy link
Copy Markdown

@kenisteward Did you push a fix to the PR?

@kenisteward
Copy link
Copy Markdown
Contributor Author

@HermenOtter Not yet. It turns out that was a bug but the actual bug causing your problem was because it doesn't like typing the function as 'body' | 'response' | 'events' for correlation with passing it to the httpclient. I'm going to switch to any right now and try again. I'm not getting any errors locally with any and we get type safety with the overloads

@kenisteward
Copy link
Copy Markdown
Contributor Author

@macjohnny I think i''ll change to what you suggested for clarity in the future for others.

@kenisteward
Copy link
Copy Markdown
Contributor Author

@HermenOtter Fixed!

@HermenOtter
Copy link
Copy Markdown

@kenisteward @macjohnny I can confirm it works as expected for my application. However I did not test all combinations.

Thank you for your effort.

@kenisteward
Copy link
Copy Markdown
Contributor Author

@HermenOtter thanks for testing! Yay new features! If there are no other issues @wing328 please merge at you leisure.

@bedag-moo would love for you to test as well if you have time!

public findPetsByStatus(status: Array<string>, observe?: 'body', reportProgress?: boolean): Observable<Array<Pet>>;
public findPetsByStatus(status: Array<string>, observe?: 'response', reportProgress?: boolean): Observable<HttpResponse<Array<Pet>>>;
public findPetsByStatus(status: Array<string>, observe?: 'events', reportProgress?: boolean): Observable<HttpEvent<Array<Pet>>>;
public findPetsByStatus(status: Array<string>, observe: any = 'body', reportProgress: boolean = false ): Observable<any> {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type of observe seems too permissive here, because it would allow invocations like:

findPetsByStatus(status, observe: HttpResponse)
findPetsByStatus(status, observe: "Body")

Angular's HttpClient restricts this parameter to permitted values:

observe?: HttpObserve,

where

/**
 * @stable
 */
export type HttpObserve = 'body' | 'events' | 'response';

So we should be able to import that type, and use it ourselves? Is there a reason we can't follow angular's lead here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can't import it. I tried it myself and it did not work. You can try it in your project if you'd like and tell me if i'm doing something wrong.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also it doens't allow those invocations. you are only allowed to pass thoes specific things cause it's the string type.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the last observe: any is not counted for the invocations. only the overloads before it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bedag-moo from angular public_api.d.ts
export { HttpClient } from './src/client';

they don't export HttpObserve

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My apologies, I didn't know that typescript treats does not consider the last signature part of the overload list. Your code is fine then, sorry for not checking.

@bedag-moo
Copy link
Copy Markdown
Contributor

I'm afraid I won't have time for tests in the near future, but if it works for Hermann Otter, it very likely works for me, too.

@bedag-moo
Copy link
Copy Markdown
Contributor

This PR looks good to me.

@HermenOtter
Copy link
Copy Markdown

HermenOtter commented Nov 16, 2017

@kenisteward @bedag-moo I had more time and I came across a few warnings and a problem.
TSLint is complaining about the use of let's instead of const, as well if (httpContentTypeSelected != undefined) { != should be !== and [tslint] " should be ' (quotemark)

@kenisteward Since you changed the implementation to in the method overload, I doesn't return HttpResponse<Subject> anymore, but instead HttpResponse<any>. I am not sure if it has something to do with my version of typescript, my intellisense or a different problem.

I might be able to find some time to commit fixes to those warnings, but I don't know why the typings don't work.

@kenisteward
Copy link
Copy Markdown
Contributor Author

kenisteward commented Nov 16, 2017 via email

@HermenOtter
Copy link
Copy Markdown

@kenisteward Thanks for your reply, did you read the second paragraph of my answer? It seems like the typings are broken, while it should not be possible, did you experience the same problem?

@kenisteward
Copy link
Copy Markdown
Contributor Author

@HermenOtter I did and I'm wondering what's going on. The only reason HttpResponse would be returned is if Subject is not applied as a response type on the return. The template that generates the returntype is this:

{{#returnType}}{{{returnType}}}{{#isResponseTypeFile}}|undefined{{/isResponseTypeFile}}{{/returnType}}{{^returnType}}any{{/returnType}}

which would mean that returnType is not set for that operation.

Could i get a peak at the endpoint yaml you are using to confirm whether my hypothesis is correct?

@kenisteward
Copy link
Copy Markdown
Contributor Author

@HermenOtter I also have a sneaking suspicion I've introduced a bug with the return type for file based requests. Do you have any endpoints that return files by any chance?

@HermenOtter
Copy link
Copy Markdown

HermenOtter commented Nov 22, 2017

@kenisteward Strange, I remember it generating the method overloads with Subject as type. I do not have endpoints that return files, so I can't help you with that. I have sent you the yaml of the endpoint.

@kenisteward
Copy link
Copy Markdown
Contributor Author

@HermenOtter what do you mean when you change the types it works? You have an example?

@HermenOtter
Copy link
Copy Markdown

HermenOtter commented Nov 22, 2017

@kenisteward In a previous version it seemed to work, but it did not: causing my confusion. Could it be an allof is causing my problem(see snippet below)?

responses:
        200:
          description: "A subject"
          headers:
            ETag:
              type: string
          schema:
            type: "object"
            allOf:
            - $ref: "#/definitions/Subject"
            - type: "object"
              properties:
                links:
                  $ref: 'https://api.swaggerhub.com/...

@HermenOtter
Copy link
Copy Markdown

HermenOtter commented Nov 22, 2017

The allOf problem seems to be an issue outside the scope of this PR. I think that if @kenisteward can confirm the returning of a file in an endpoint works, the PR can be merged. @wing328

@wing328
Copy link
Copy Markdown
Contributor

wing328 commented Nov 22, 2017

I'll merge it tomorrow (Thur) if no one has further feedback or question on this PR.

@wing328 wing328 merged commit 8eb33f9 into swagger-api:master Nov 23, 2017
@kenisteward
Copy link
Copy Markdown
Contributor Author

kenisteward commented Nov 23, 2017 via email

@HermenOtter
Copy link
Copy Markdown

Thank you @wing328!

@kenisteward
Copy link
Copy Markdown
Contributor Author

kenisteward commented Nov 24, 2017

@HermenOtter As a note, the master branch currently only supports features for OAS 2.0. allOf, oneOf, anyOf, not are all OAS 3.0 features. That should be implemented on the 3.0.0 branch if we were to support it.

docs https://swagger.io/docs/specification/data-models/oneof-anyof-allof-not/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants