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

text/event-stream not supported #1375

Open
rome-user opened this issue Dec 24, 2024 · 4 comments
Open

text/event-stream not supported #1375

rome-user opened this issue Dec 24, 2024 · 4 comments
Labels
bug Something isn't working

Comments

@rome-user
Copy link

What version of ogen are you using?

$ go list -m github.com/ogen-go/ogen
github.com/ogen-go/ogen v1.8.1

Can this issue be reproduced with the latest version?

Yes

What did you do?

Consider the following schema. Save it as openapi.yaml.

openapi: 3.0.0
info:
  title: Example API
  version: "1.0"
paths:
  /events:
    get:
      summary: SSE example
      responses:
        "200":
          description: OK
          content:
            text/event-stream:
              schema:
                type: string

Run the following terminal commands

$ go mod init repro
$ go get github.com/ogen-go/ogen/cmd/ogen
$ go run github.com/ogen-go/ogen/cmd/ogen --target gen/api -package api --clean openapi.yaml
$ go mod tidy

Create a main.go file with the following contents.

Click to view server implementation
package main

import (
	"context"
	"io"
	"log"
	"net/http"
	"time"

	"repro/api"
)

func main() {
	srv, err := api.NewServer(&service{})
	if err != nil {
		log.Fatal(err)
	}

	if err := http.ListenAndServe(":8080", srv); err != nil {
		log.Fatal(err)
	}
}

type service struct{}

func (s *service) EventsGet(ctx context.Context) (api.EventsGetOK, error) {
	r, w := io.Pipe()

	go func() {
		defer w.Close()
		for ctx.Err() == nil {
			select {
			case <-ctx.Done():
				return
			case <-time.After(1 * time.Second):
				w.Write([]byte("data: ping\n\n"))
			}
		}
	}()

	return api.EventsGetOK{Data: r}, nil
}

Finally, start the server.

$ go run main.go

What did you expect to see?

Client can stream the response. e.g.

$ curl -N http://localhost:8080/events
data: ping
data: ping
...

What did you see instead?

The generated code in oas_response_encoders_gen.go looks like the following.

Click to view generated code
func encodeEventsGetResponse(response EventsGetOK, w http.ResponseWriter, span trace.Span) error {
	w.Header().Set("Content-Type", "text/event-stream")
	w.WriteHeader(200)
	span.SetStatus(codes.Ok, http.StatusText(200))

	writer := w
	if _, err := io.Copy(writer, response); err != nil {
		return errors.Wrap(err, "write")
	}

	return nil
}

The call to io.Copy prevents streaming of response. This results in clients not receiving data.

@rome-user rome-user added the bug Something isn't working label Dec 24, 2024
@gedw99
Copy link

gedw99 commented Jan 22, 2025

Your trying to do sync push ?

I am also doing protocol buffers to open ali for pull and push ( over open api ).

Thee is a thing called asyncapi that is designed for openapi but for async . It’s got many more foot guns though .

Would love to know your use case

@rokf
Copy link

rokf commented Jan 26, 2025

I'm personally interested in this functionality so that I could generate boilerplate handler code for https://data-star.dev with ogen.

What I do currently is that I have two OpenAPI specifications for an application - one API that returns HTML for the GUI and one that returns JSON for M2M communication.

With support for text/event-stream I could squeeze in the SSE endpoints for Datastar into my ogen HTML API - currently I need a custom set of handlers next to those managed by ogen and combine them all with a mux.

@rokf
Copy link

rokf commented Feb 14, 2025

As a workaround you can use middleware to pass and retrieve the raw request and response objects - #1252.

I've tested this approach with https://github.com/starfederation/datastar/tree/main/sdk/go and it works fine.

The only issue I found was that Ogen writes an error log saying that there's an superfluous header write once the stream is finished - it doesn't seem to break anything though.

@gedw99
Copy link

gedw99 commented Feb 16, 2025

hey @rokf your use case is identical to mine :) I also use datastar

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants