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

🤗 [Question]: Calling other endpoints without network #2949

Closed
3 tasks done
nexovec opened this issue Mar 31, 2024 · 13 comments
Closed
3 tasks done

🤗 [Question]: Calling other endpoints without network #2949

nexovec opened this issue Mar 31, 2024 · 13 comments

Comments

@nexovec
Copy link

nexovec commented Mar 31, 2024

Question Description

Hi,
Is it possible to call another route from the same fiber server without going through the network?

In the snippet below, I would like to call /api/endpoint from the /ui that returns a nice UI with the result of the api call (It needs to set fiber to being awesome just in case someone forgot to do it), and to call it with all the registered middlewares and the original request headers, without going through the network, because it seems like an unneeded step.

Is this possible?

Code Snippet (optional)

package main

import "github.com/gofiber/fiber/v3"
import "log"

func main() {
  app := fiber.New()

  // An example to describe the question
        app.Get("/ui", func(c *fiber.Ctx) error {
                ret := req.Get("/api/endpoint"), or something // TODO: help needed
		return templates.WelcomeUI(ret).Render(c.Context() ... )
	})
        api := fiber.Group("/api", AdminOnlyMw)
	api.Get("/endpoint", func(c *fiber.Ctx) error {
                technology.fiber.SetAwesome(true)
		return c.SendText("fiber is awesome")
	})

  log.Fatal(app.Listen(":3000"))
}

Checklist:

  • I agree to follow Fiber's Code of Conduct.
  • I have checked for existing issues that describe my questions prior to opening this one.
  • I understand that improperly formatted questions may be closed without explanation.
Copy link

welcome bot commented Mar 31, 2024

Thanks for opening your first issue here! 🎉 Be sure to follow the issue template! If you need help or want to chat with us, join us on Discord https://gofiber.io/discord

@gaby
Copy link
Member

gaby commented Mar 31, 2024

@nexovec Why do you need to call another handler just to set a boolean? Move that logic to a separate function and call that function from both handlers.

@nexovec
Copy link
Author

nexovec commented Mar 31, 2024

@gaby I am aiming at having less indirection and less boilerplate code for actually dispatching an HTTP request, so having a function for setting a boolean is making this worse, not better. The routes being called are always depending on the expected middlewares being called too. Needless to say, my use case is more complicated, with about 3–4 levels of this indirection that I just can't do anything about(think frontend calling a backend calling an email dispatcher calling authorization).

I would like to "call the router," not the function, ideally while staying inside the fiber framework and not going through the network. Is the purpose of the question clear?

@gaby
Copy link
Member

gaby commented Mar 31, 2024

@nexovec Yes, it's clear

@ReneWerner87 Is this even possible? User is using v3 already.

@ReneWerner87
Copy link
Member

In v2 it was possible with
https://docs.gofiber.io/api/ctx#redirecttoroute
and I think the function is still there.

@nexovec
Copy link
Author

nexovec commented Apr 1, 2024

In v2 it was possible with https://docs.gofiber.io/api/ctx#redirecttoroute and I think the function is still there.

My understanding is these redirect methods do a client side redirect (basically responding to the original request with a 302). Am I wrong?

@nexovec
Copy link
Author

nexovec commented Apr 14, 2024

I am still looking for a solution to this issue. To stimulate discussion and give a better idea, this is how I think this could look like:

package main

import "github.com/gofiber/fiber/v3"
import "log"

func main() {
  app := fiber.New()

  // An example to describe the question
        app.Get("/ui", func(c *fiber.Ctx) error {
                response, err := c.CallRoute("/api/endpoint")
		return templates.WelcomeUI(response).Render(c.Context() ... )
	})
        api := fiber.Group("/api", AdminOnlyMw)
	api.Get("/endpoint", func(c *fiber.Ctx) error {
                technology.fiber.SetAwesome(true)
		return c.SendText("fiber is awesome")
	})

  log.Fatal(app.Listen(":3000"))
}

The method <fiber.Ctx>.CallRoute would call another route on the same server without going through the network at all. It would pass the original requests information to the newly called route. In this case, there should also exist a fiber.CallRoute function that would enable you to call a route without having a fiber context object (by having to specify all the request information as parameters).

@balexandre
Copy link

my 2 cents here,

if you create a controller a-like, wouldn't be better to just call it from within your call?

example:

package main

import "github.com/gofiber/fiber/v3"
import "log"

func main() {
  app := fiber.New()

  // An example to describe the question
  app.Get("/ui", func(c *fiber.Ctx) error {
    textToSend := setEndpointText(true)
    return templates.WelcomeUI(textToSend).Render(c.Context() ... )
  })

  api := fiber.Group("/api", AdminOnlyMw)
  api.Get("/endpoint", func(c *fiber.Ctx) error {
    textToSend := setEndpointText(true)
    return c.SendText(textToSend)
  })

  log.Fatal(app.Listen(":3000"))
}

func setEndpointText(txt string) string {
  technology.fiber.SetAwesome(true)
  return "fiber is awesome"
}

in a way you would not spend time in a request by redirecting it, and you end up encapsulating the data you want in both cases into just one internal call

@kbiits
Copy link

kbiits commented May 4, 2024

@nexovec You shouldn't look for the answers in a web framework library.

Things you may need to consider is it the network overhead really blocking you? If not, just go with the network call, especially if it happens on server side I think the latency should be negligible for your users.

What if the network call is really blocking you? You should refactor your code. You can create a pipeline pattern to make the behavior similar to middleware in fiber, and you should abstract your code so you can reuse it inside fiber middlewares and remove duplicates on your codebase.

@nexovec
Copy link
Author

nexovec commented May 4, 2024

@kbiits the primary concern is reliability of the connection, the latency is a really bad problem and you shouldn't need to do a client side redirect unless you specifically need to, but the fact the request might not even arrive is much more troubling.

I just have to comment on how bad of an architectural decision it is to have 2 separate middleware systems, even worse when you make the other one to supplement the first one. Fiber is already doing this for me, it makes me really happy I don't have to deal with this myself.

I like code locality and so I don't have the slightest reason to abstract away from the fiber API either, I like it, I don't have duplicity problems.

In fact, I'd like to rely on fiber to provide faculties to simulate requests and interfaces for testing and introspection, and this falls well within the scope of what a framework should offer, if for nothing else than how closely coupled those are to the framework.

The only thing I'm asking for rn is to be able to "call a route" as you would with a function.

(Not getting confrontational, just hard disagree)

Is this understandable?

@kbiits
Copy link

kbiits commented May 5, 2024

Yes, it's all clear @nexovec. But I don't see any reason for fiber to provide such API. Why does fiber need to provide an API to simulate requests without a network? If it's used for testing, yes, it makes sense, but I don't get it to expose such API to the fiber users. There are many ways for fiber users to test their code without relying on the API you mentioned. Also, your usecase is very niche.

Nevertheless, I think you can still use *fiber.App.Stack() method which returns fiber stack routes to achieve what you want. You need to filter the routes that you want and call the handlers just like you call functions.

image

@nexovec
Copy link
Author

nexovec commented May 5, 2024

Nevertheless, I think you can still use *fiber.App.Stack() method

@kbiits This is exactly what I imagined! Thank you so much. It's a bit clumsy to use this directly, I will likely write a convenience wrapper for this. This is massively helpful.

Also, your usecase is very niche.

This is a bit sad to hear. To me going through network when you don't have to is an extra failure point, I feel a bit of joy anytime I can avoid it.

@nexovec nexovec closed this as completed May 5, 2024
@kbiits
Copy link

kbiits commented May 5, 2024

@kbiits This is exactly what I imagined! Thank you so much. It's a bit clumsy to use this directly, I will likely write a convenience wrapper for this. This is massively helpful.

Glad to help.

This is a bit sad to hear. To me going through network when you don't have to is an extra failure point, I feel a bit of joy anytime I can avoid it.

Yes, I really understand your point. We engineers of course don't want to add overhead to our system. But, objectively speaking, fiber also need to keep their library to be as simple as it can.

All the best for your projects

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

No branches or pull requests

5 participants