OpenAPITools / OpenAPITools/openapi-generator
[REQ] [go-server] Services knowing about HTTP is questionable
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 26.8k
- Forks
- 7.7k
- PR merge metrics
- PR metrics pending
Description
Is your feature request related to a problem? Please describe.
Let's look at the service method signatures:
func (s *UserApiService) CreateUser(ctx context.Context, user User) (ImplResponse, error) {
}
The method returns a ImplResponse, carrying a HTTP status code. I see two problems with this.
The first one .... really, really minor: why does a method return an implementation object? It should return an interface, and ImplResponse would be an implementation of that interface.
Now to the other, bigger one.
Imo there's an architectural problem with the idea of controllers and services.
What is the idea of controllers and services?
The idea of the separation between controllers and services is (imo, pls enlighten me otherwise):
- controllers hold all the connection logic, specific to http in this case.
- services hold the business logic solely. They don't know anything about HTTP status codes. They return model classes and errors
What's the current state?
Services return response objects, carrying HTTP status codes. Making services HTTP-dependant.
What's wrong with this?
Imagine you have a REST API (openapi) and e.g. a gRPC API. The services do exactly the same, we just have different controllers.
With the current design this forces us to have three layers:
- the openapi-controller layer
- the openapi-service layer (HTTP specific)
- our actual service layer independent of HTTP knowledge.
That middle layer should not be necessary, it bloats up the code.
Describe the solution you'd like
Keeping it implementation-independent, it would be best (also just imo, please enlighten me otherwise) to have service methods like this:
func (s *UserApiService) CreateUser(ctx context.Context, user User) (interface{}, error) {
}
The interface{} is one of the generated model classes, ready for serialization.
Where error can be of a new interface type:
type Error interface {
Error()
IsBadUserInput()
IsInternal()
IsUpstream()
// ...
}
Then the controller can check whether the returned error is of that interface and map to corresponding HTTP status codes and if not simply return a 500:
// CreateUser - Create user
func (c *UserApiController) CreateUser(w http.ResponseWriter, r *http.Request) {
user := &User{}
if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
result, err := c.service.CreateUser(r.Context(), *user)
// If an error occurred, encode the error with the status code
if err != nil {
if knownErr, ok := err.(Error); ok {
if knownErr.IsBadUserInput() {
EncodeJSONResponse(err.Error(), &http.StatusBadRequest, w)
} else if knownErr.IsInternal() {
// ...
}
// aso.
} else {
EncodeJSONResponse(err.Error(), &http.StatusInternalServerError, w)
}
} else {
// If no error, encode the body and the result code
EncodeJSONResponse(result, &http.StatusOK, w)
}
}
Describe alternatives you've considered
Not alternatives, but workarounds.
One workaround is the aforementioned, three-layer-architecture, that bloats up the code.
Another one is ignoring the ImplResponse:
- either redefine
ImplResponsetointerface{} - or ignore the status code in
ImplResponseand only use body
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in the go-server generation path by tracing UserApiService.CreateUser, ImplResponse, and UserApiController.CreateUser. Review how services and controllers currently exchange response bodies, errors, and HTTP status codes. Done would mean an agreed implementation-independent service boundary with corresponding generated server behavior, rather than a design proposal alone.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- api, backend-api-design
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100