As we've seen on a part of the [[Getting Started]] section the client (or server) can also block/wait and catch a response from the remote side anywhere in the application flow, you are not limited to the asynchronous event-driven API. Both methods and styles are used in a typical, common, application. ## The Conn Ask Use this method when you have access to the connection value that you want to ask for. The `Conn.Ask` and `NSConn.Ask` methods do exactly that. In this section you will learn how to create a question-answer flow and how to manage incoming remote event errors, remember? Event callback can return an `error` too. At this example, for the shake of simplicity, we will set to a client the role to ask and server to reply, but this can be converted to a bidirectional flow too, each `NSConn` and `Conn`'s method can be used by both server and client sides. The application is fairly simple, the client will provide a date `month-day-year` and server will reply back if its a work day or if the date is not valid for work, it's a day off or the provided time format is invalid. ## Create & run the Server Let's dive in by defining our server-side. ```go const namespace = "default" var errDayOff = errors.New("day off") func runServer() { websocketServer := neffos.New( gorilla.DefaultUpgrader, neffos.Namespaces{ namespace: neffos.Events{ "workday": func(c *neffos.NSConn, msg neffos.Message) error { date := string(msg.Body) t, err := time.Parse("01-02-2006", date) if err != nil { return err } weekday := t.Weekday() if weekday == time.Saturday || weekday == time.Sunday { return errDayOff } responseText := fmt.Sprintf("it's %s, do your job.", weekday) return neffos.Reply([]byte(responseText)) }, }, }) router := http.NewServeMux() router.Handle("/", websocketServer) log.Println("Serving websockets on localhost:8080") log.Fatal(http.ListenAndServe(":8080", router)) } ``` ## Create & run the Client Continue with our client-side. ```go func runClient() { // Make the client error-aware of the `errDayoff` // If that's missing the `Message.Err.Error() string` would still match it // but comparison of err == errDayOff wouldn't be a valid one. neffos.RegisterKnownError(errDayOff) ctx := context.Background() client, err := neffos.Dial(ctx, gorilla.DefaultDialer, "ws://localhost:8080", // Empty events because client does not need an event callback in this case. // The client is only uses the `Ask` method which allows the caller // to manage the response manually even if a local event is not registered at all. neffos.Namespaces{namespace: neffos.Events{}}, ) if err != nil { panic(err) } c, err := client.Connect(ctx, namespace) if err != nil { panic(err) } fmt.Println("Please specify a date of format: mm-dd-yyyy") for { fmt.Print(">> ") var date string fmt.Scanln(&date) response, err := c.Ask(ctx, "workday", []byte(date)) if err != nil { if err == errDayOff { // >> 06-29-2019 // it's a day off! fmt.Println("it's a day off!") } else { // >> 13-29-2019 // error received: parsing time "13-29-2019": month out of range fmt.Printf("error received: %v\n", err) } continue } // >> 06-24-2019 // it's Monday, do your job. fmt.Println(string(response.Body)) } } ``` Note that the error managment works the same way with the event-driven API too. Instead of `response, [err] := c.Ask(...)` the `err` error is stored at the incoming `Message.Err` field, a quick view: ```go func onSomething(c *neffos.NSConn, msg neffos.Message) error { if msg.Err != nil { if msg.Err == errDayOff { // [handle errDayoff...] } } } ``` Read more at [[Errors]] section. ## The Server Ask Use this method when you: * do NOT have access to the connection value that you want to ask for or * want to wait for a reply from a client that may be served by other neffos server (when your app is [scaled-out](Scale-out)). The `Server.Ask` method is like `Server.Broadcast` but it blocks until response, from a specific connection (when `"msg.To"` is filled) or from the first connection which will reply to this `"msg"`. 1. Accepts a context for deadline as its first input argument. 2. The second argument is the request message which should be sent to a specific namespace:event like the `Conn/NSConn.Ask`. ```go Ask(ctx context.Context, msg Message) (Message, error) ``` Example Client Event: ```go "onAsk": func(c *neffos.NSConn, msg neffos.Message) error { return neffos.Reply([]byte("I am fine")) } ``` **Usage** ```go response, err := websocketServer.Ask(context.TODO(), neffos.Message{ // To: toConnID, Namespace: namespace, Event: "onAsk", Body: []byte("how are you?"), }) if err != nil { // [handle err...] } ``` response.Body would be `[]byte("I am fine")`.