Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ability to attach macros to generated types and methods #383

Open
HonQii opened this issue Nov 17, 2023 · 9 comments
Open

Ability to attach macros to generated types and methods #383

HonQii opened this issue Nov 17, 2023 · 9 comments
Labels
status/needs-design Needs further discussion and a concrete proposal.
Milestone

Comments

@HonQii
Copy link

HonQii commented Nov 17, 2023

It would be nice to be able to add macros to the generated Schema and API requests in order to extend the functionality, e.g. all of my request return structures have an optional error field, so if I could add a macro that would allow me to extend the support for a protocol for them, I could easily handle the error uniformly

@simonjbeaumont
Copy link
Collaborator

@HonQii could you elaborate a little on what you'd like to see? You can currently write extensions on the types generated and conform them to protocols that you define. Are you asking for the protocol conformance to be automatically added for you by the generator, potentially by specifying a macro you'd like to run in the generator config?

Maybe you could provide a quick snippet of how you'd like the generated code to be different.

@czechboy0
Copy link
Collaborator

Maybe @HonQii means that they could configure some macro name to be automatically attached to all generated types, similar to how we allow adding additional imports? But the user would still need to provide the macro implementation.

(Which is an interesting idea that would indeed provide quite a lot of flexibility for sufficiently motivated adopters.)

@czechboy0 czechboy0 added the status/triage Collecting information required to triage the issue. label Nov 17, 2023
@HonQii
Copy link
Author

HonQii commented Nov 20, 2023

Maybe @HonQii means that they could configure some macro name to be automatically attached to all generated types, similar to how we allow adding additional imports? But the user would still need to provide the macro implementation.🔄  ❓

(Which is an interesting idea that would indeed provide quite a lot of flexibility for sufficiently motivated adopters.)🔄  ❓

Right, what I mean is that I can configure macros to the generated Schema as well as the Client so that I can do some wrapping. An example:

// Each of my request response structures will have an error field with a message and code if there is an error
struct BaseResponse {
      var error: Error? // empty if there is no error.
}

Normally I would need to define a protocol for all structures to follow, and then I could handle these errors consistently. But in the case of autogeneration, I think it's more appropriate to use a macro for this purpose

Similarly, I need a layer of encapsulation for each request in the client to handle exceptions, which can also be accomplished using a macro

@czechboy0
Copy link
Collaborator

Can you be even more specific here, for example use a simple OpenAPI document, generate code with it, and then outline what exact changes you'd like to see in the generated code? I'm still not entirely sure I understand.

@simonjbeaumont
Copy link
Collaborator

// Each of my request response structures will have an error field with a message and code if there is an error
struct BaseResponse {
      var error: Error? // empty if there is no error.
}

OOI, are you the author of this document? Because, if so, for this example, you could have the generated code make use of shared types by writing this in the OpenAPI document itself. For example, you can make use of of a common type in #/components/schemas, or you could define a shared response in #/components/responses, or you could try and combine these with an allOf1.

Concretely, if you make use of references in the OpenAPI document, then the generator will use a single type. This allows for you to write extensions on this common type once.

Footnotes

  1. https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#composition-and-inheritance-polymorphism

@HonQii
Copy link
Author

HonQii commented Nov 28, 2023

Can you be even more specific here, for example use a simple OpenAPI document, generate code with it, and then outline what exact changes you'd like to see in the generated code? I'm still not entirely sure I understand.您能否在这里更具体一点,例如使用一个简单的 OpenAPI 文档,用它生成代码,然后概述您希望在生成的代码中看到哪些确切的更改?我仍然不完全确定我是否理解。

For example, I'm using the Combine framework to encapsulate a lot of UI components, so I'd like to be able to return web requests through the Publisher, and I'm now generating my own batch of code using the Plugin, which is formatted as follows:

func getMyInfo(_ query: Components.Schemas.GetMyInfoReq) -> AnyPublisher<Components.Schemas.GetMyInfoResp, Error> {
        Future { promise in
            Task {
                do {
                    let resp = try await self.filterSuccess(await self.client.getMyInfo(.init(body: .json(query))))
                    promise(.success(resp))
                } catch {
                    promise(.failure(error))
                }
            }
        }
        .eraseToAnyPublisher()
    }

If I could support macros when generating swift-openapi-generator, I could generate the methods directly from the macros, and instead of having to convert the results using the filterSuccess method, I could just make each structure in the Schema adhere to a certain protocol, and use Combine's filter function to handle the errors.

@HonQii
Copy link
Author

HonQii commented Nov 28, 2023

// Each of my request response structures will have an error field with a message and code if there is an error
struct BaseResponse {
      var error: Error? // empty if there is no error.
}

OOI, are you the author of this document? Because, if so, for this example, you could have the generated code make use of shared types by writing this in the OpenAPI document itself. For example, you can make use of of a common type in #/components/schemas, or you could define a shared response in #/components/responses, or you could try and combine these with an allOf1.OOI,你是本文档的作者吗?因为,如果是这样,对于此示例,您可以通过将其编写在 OpenAPI 文档本身中来让生成的代码使用共享类型。例如,您可以在 中使用 中的通用类型,也可以在 中定义共享响应,或者可以尝试将这些响应 #/components/schemasallOf 1 . #/components/responses

Concretely, if you make use of references in the OpenAPI document, then the generator will use a single type. This allows for you to write extensions on this common type once.具体来说,如果使用 OpenAPI 文档中的引用,则生成器将使用单个类型。这允许您在此常见类型上编写一次扩展。

  1. https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#composition-and-inheritance-polymorphism

Sorry, I didn't write it.

@czechboy0
Copy link
Collaborator

If I understand correctly, you'd be interested in being able to use a macro to generate a variant of every client method that uses Combine, like you outlined above?

If so, that seems very similar to the "add async variant" macro here: https://github.com/apple/swift-syntax/blob/main/Examples/Sources/MacroExamples/Implementation/Peer/AddAsyncMacro.swift

The question is where exactly the generator would add the @UserSpecifiedMacro macro, probably in the extension, so that the macro could emit an implementation (couldn't be on the func declaration in the protocol). I think that could work, and can be done post-1.0 as a non-breaking change, as this would be fully opt-in through the config file, similar to additionalImports.

@czechboy0 czechboy0 changed the title Can I add some parameters to specify that the generated Schema and API support swift macros? Ability to attach macros to generated types and methods Nov 29, 2023
@czechboy0
Copy link
Collaborator

Okay, renaming this issue to track the general desire to attach macros to generated types and functions.

@czechboy0 czechboy0 added status/needs-design Needs further discussion and a concrete proposal. and removed status/triage Collecting information required to triage the issue. labels Nov 29, 2023
@czechboy0 czechboy0 added this to the Post-1.0 milestone Nov 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status/needs-design Needs further discussion and a concrete proposal.
Projects
None yet
Development

No branches or pull requests

3 participants