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

Are there frameworks based on fasthttp? #9

Closed
thedrow opened this issue Nov 30, 2015 · 29 comments
Closed

Are there frameworks based on fasthttp? #9

thedrow opened this issue Nov 30, 2015 · 29 comments
Labels

Comments

@thedrow
Copy link

thedrow commented Nov 30, 2015

I mainly need a good router but a complete framework will be nice.

@valyala
Copy link
Owner

valyala commented Nov 30, 2015

Unfortunately there are no frameworks with fasthttp support yet :( Because fasthttp is very young - it has been started a month ago.

Everybody may help by filing feature requests to their favorite frameworks, asking to add support for fasthttp. I already filed such a request for httprouter.

@mathvav
Copy link

mathvav commented Dec 5, 2015

Hmm. I just stumbled upon this project 2 minutes ago when looking at fasthttp.

I'm getting frustrated with many Go frameworks:

  • There are hundreds of "mom and pop shop" frameworks around that are not maintained. Even a few more popular like Martini are left untouched.
  • Many are based on slow routers.
  • Many are insecure. Even Revel is subject to replay attacks with their client-stored session data.
  • Many lack middleware for subrouters (you can't have all requests to /account//account/* all use a separate middleware).
  • Many have tens if not hundreds of middleware packages that are all duplicates and obsolete and unmaintained.

I'm somewhat interested in building a framework for this. I've already been building a very simple framework that has built in security features, such as rate limiting and authentication for a user built in.

It'd be nice to have a refreshing restart of the middleware ecosystem, although some would argue more or less removing support for a large sea of code is a bad idea, even if is mostly unmaintained. I guess I could fork other middleware and port/improve them.

I have a few questions:

  • @valyala: do you honestly think fasthttp is stable enough for production, or even near that point? I want to build my framework using somewhat stable software, although bleeding edge is fun if the original developer can help. Are you going to be able to maintain this library when more bug reports start filing in? It seems massive already.
  • If I do choose to build upon fasthttp: Would both of you be interesting in help alpha-testing and giving feedback to such a project, along with giving very simple API design feedback before I even release it?
  • To @valyala again: how did you promote this project so well? It already has 1.2K stars, even without a single framework or a few months on this project. Essential to a framework is getting people to help support it. Those people would also help support fasthttp.

Thoughts? Comments? Questions?

@thedrow
Copy link
Author

thedrow commented Dec 5, 2015

I think there is a good case for a Go web framework that is on one hand very fast but on the other hand can increase our productivity as developers. That's the reason this project is so popular. It provides the building blocks to create such a framework.
It's not easy, especially for beginners in Go like me to write good concise HTTP servers without proper abstractions.
The approach taken by Martini is optimal in my opinion, it does have one failing point. It's slow due to the extensive usage of reflection.
A web framework with dependency injection implemented with code generation (like https://github.com/square/dagger for Java) would boost productivity while not forgoing performance.
I'd be willing to provide feedback on the API design and test the new framework.

@mathvav
Copy link

mathvav commented Dec 7, 2015

I like the Martini style as it looks clean, although the documentation with so much reflexion is cumbersome and it makes code completion look quite odd. That's not mentioning speed trade offs.

It's not easy, especially for beginners in Go like me to write good concise HTTP servers without proper abstractions.

Yes, although I might argue that fine grained control is better than abstracting too much away, especially when it may be “leaky abstraction” (a reference to a Joel on Software post). If you have to think about what goes on during the request, it can be cumbersome when the framework doesn't let you control every header and every part to tweak (when you need it) how your API/website functions. The challenge is finding good defaults and having interfaces to change things without too much thought on the programmers behalf.

To be perfectly clear—I don't think a simplest for beginner would be the best route for a framework built on some of the fastest server code around open source in Go. I'd expect the demographic to be more experienced users building for medium to large scale production environment.


Can I ask you what API you would recommend for functions?

I think it'll be something like this:

var s framework.Service = framework.newService()

func indexHandler(c *framework.Context) {
    params := c.Params()
    c.WriteHTML("<html></html>")
}

func init() {
    s.HandleGET("/", indexHandler)
}

func main() {
    s.run(framework.Settings{})
}

I use init to break handlers into separate files easily.


RE dependency injection: I'd imagine this would be a job for a side library, not this itself. I'm not exactly sure what you're proposing for this to be linked into the framework. Can you elaborate?

@valyala
Copy link
Owner

valyala commented Dec 7, 2015

do you honestly think fasthttp is stable enough for production, or even near that point?

Yes, it already serves high volume traffic in production on multiple microservices.

I want to build my framework using somewhat stable software, although bleeding edge is fun if the original developer can help. Are you going to be able to maintain this library when more bug reports start filing in? It seems massive already.

I'm ready to help developing decent router for fasthttp (if it satisfies the following requirements: fast + clear API. See below for details). I'm going to maintain fasthttp in the future.

If I do choose to build upon fasthttp: Would both of you be interesting in help alpha-testing and giving feedback to such a project, along with giving very simple API design feedback before I even release it?

I have zero experience with http routers (both as user and API designer), so cannot distinguish between good and bad API for http routers. So probably somebody more experienced should help you with this.

how did you promote this project so well?

Just posted an announcement on golang-nuts.

I'd recommend avoiding the following stuff, since it usually increases code complexity and complicates debugging. Especially in the hands of inexperienced developers:

  • dependency injection
  • code generation
  • reflection

Performance optimization may be added to this list as well. But this is good trade-off for good fasthttp performance :)

@mathvav
Copy link

mathvav commented Dec 7, 2015

I'm ready to help developing decent router for fasthttp (if it satisfies the following requirements: fast + clear API. See below for details). I'm going to maintain fasthttp in the future.

Do you see a need to build an entirely new router? If httprouter isn't too entangled with the standard http library, I'd like to port it since it is super fast compared to some other libraries.

Anyway, I'm curious what you consider to be a "simple" API—are you talking about essential complexity or accidental complexity? To what degree? And no, code generation is not a force I want to mess with :). I don't like when you have to download new tools to use a framework when it's not needed.

@thedrow
Copy link
Author

thedrow commented Dec 7, 2015

I don't know anything other than dependency inversion that can isolate a component correctly.
So if code generation is a no-go and reflection will make the API slower so it's obvious that it's not a good solution for injecting dependencies, what is the alternative?

@mathvav
Copy link

mathvav commented Dec 7, 2015

Hold on; I'm slightly confused now. Inject what? Are we talking about handlers or an extra API feature unrelated to the core? I was talking about handlers and I thought you were talking about an unrelated feature. If you're talking about handlers, can you explain why/what you would inject related to the handlers that needs to be built into the framework?

I think we're talking about different things.

@thedrow
Copy link
Author

thedrow commented Dec 7, 2015

I'm talking about injecting dependencies for a request such as the database connection pool.

@mathvav
Copy link

mathvav commented Dec 7, 2015

Is there a reason that has to be integrated into the framework or can it be a separate library, like Dagger?

@thedrow
Copy link
Author

thedrow commented Dec 8, 2015

Productivity. Plain and simple.
We can write the DI library and the HTTP framework and integrate them.
I do like the batteries included approach though.

@valyala
Copy link
Owner

valyala commented Dec 8, 2015

Do you see a need to build an entirely new router? If httprouter isn't too entangled with the standard http library, I'd like to port it since it is super fast compared to some other libraries.

Actually, httprouter's author, @julienschmidt, left the following comment on the feature request for adding fasthttp support to httprouter:

I think the best option would be to maintain a fork for fasthttp instead. I'd be happy to do that as soon as I fixed some stuff here in the main repo.

As for dependency injection, reflection, code generation and other bikeshedding approaches for http router, go on and implement routers with these features (or anti-features, depending on personal opinions :) )! While I don't like these 'features', there are a lot of people who want using them.

I'm talking about injecting dependencies for a request such as the database connection pool.

I usually create a separate package exposing database-related API and just use it in request handlers.
This allows avoiding debugging nightmare usually related to dependency injection (and other 'magic' approaches) :)

@mathvav
Copy link

mathvav commented Dec 9, 2015

You don't like magic? Aww, no fun! :)

I usually create a separate package exposing database-related API and just use it in request handlers.

This allows avoiding debugging nightmare usually related to dependency injection (and other 'magic' approaches) :)

How do you mock the database functions without dependency injection? Wouldn't you have to create a mock object for the database functions and then inject this object into the handlers for unit testing? That's what I think of when I think of DI is mocking for unit testing, although I suppose it could be used for other things.

Anyway, the only dependency injection functionality I would want to build in is if we integrated a testing features set, which is down the road, but would be useful as debugging handlers are very difficult to do.


More short future: I am thinking for httprouter that we request that we create an interface for all http communications. The only times a router should have to deal with the http connection are:

  • Getting the URI and HTTP method
  • Sending redirects/not found/wrong methods
  • Invoking a handler (in this case the only router specific thing is the http objects passed to the handler itself)

We wouldn't be able to do everything through an interface, but keeping everything contained would make it easier to update with the fork if we could separate the parts a bit more.

On GitHub: Manual collision "fixing" will be a near daily occurrence when pulling from upstream, but it'll mostly he function declarations that cause the issues.

@valyala
Copy link
Owner

valyala commented Dec 9, 2015

How do you mock the database functions without dependency injection?

I don't mock database functions - I just connect to test database in tests :)

While dependency injection is good for unit tests, it is not so good for integration tests and production debugging.

Additionally, I don't like mocks, since:

  • Their functionality is usually far from real objects. So unit tests tend to skip the real code paths hit in production.
  • Unit tests built on mocks instead of real objects frequently break when the tested code is modified in insignificant ways (aka small refactoring).
  • Mocks must be always kept in sync with real objects. This requires additional code and time without any visible benefits.
  • Mocks require superfluous interfaces, which are used only in unit tests, but are unnecessary (complication) in production code.

@valyala
Copy link
Owner

valyala commented Dec 16, 2015

FYI, try the first router based on fasthttp - https://github.com/buaazp/fasthttprouter . Thanks, @buaazp!

@mathvav
Copy link

mathvav commented Dec 16, 2015

I saw that, and it looks like a good start. I'm hoping to get a start this Sunday as I've been busy tidying things up before the end of the year and getting ready for the holidays. I'll have some full days in the next two weeks to chip out some parts and possibly even get a very simple, but working, framework released to get feedback before polishing and packaging an alpha for official release.

@mathvav
Copy link

mathvav commented Feb 2, 2016

Status update:

I'm starting development on this again after a week break (this is a side project so development is slow). Currently at 1666 LOC; most of the remaining API planned out. Expecting to double in size after tests (which are mostly copy/paste and not hard architectural decisions).

I've built it so it can be used on top of fasthttprouter/fasthttp OR Gin. Yes, a framework on a framework is redundant, but it's meant so people can use Gin's handlers with my framework to help make porting smoother. In addition, it might be more appealing to use fasthttp if they know they can easily switch to more stable software in emergencies.

The rest of the work is tiny implementation details/small refactorings, docs, testing, etc. that should be done before it goes public.

I'm emphasizing stability and prettiness at first, but later I will start optimizing. I have a few places that sync.Pools will be used, but are not implemented yet because of time constraints.

@valyala
Copy link
Owner

valyala commented Feb 3, 2016

@Anon-Penguin , this sounds cool! Keep it up!

@mathvav
Copy link

mathvav commented Feb 14, 2016

At home sick, thinking about API and I want your opinions.

The current API passes the handler a Ctx (context) object that has various functions to get details about the request and respond to the request.

However, I can't figure out a clean way to handle responses. I have refactored it a few times feeling unhappy with every iteration.

I'm trying to get the user to use functions instead of response codes; they would do ctx.RespondOK("Hello world!") instead of ctx.Respond(200, "Hello World!"). The motive with this idea is to reduce errors by making a common set of functions that are always safe to use; it won't compile if it's not a valid status code.

Functions like these cause two issues:

  • It causes a cluttered API with repeated API calls for string arguments, byte arguments, and no-body arguments (not fun to read two pages of copied/pasted function names with slightly different arguments).
  • It forces a different API for third party marshallers (JSON, XML, etc). If I built some of these in, the API would become even more cluttered.

My solution was to create responder objects for each type of response that you can use like this—

// S = service object
s.GET("/hello", func(c *pkg.Ctx) {
    pkg.ResString{c}.StatusOK("Your request was responded to correctly!")
})

(ResString is a struct with a single value.)

Does this syntax feel heavy? Thoughts?

Am I completely overthinking this with having separate functions for each status code? I don't know if the extra typing/remembering (presuming you don't have code completion) is outweighs the benefits of less unnoticed typos.


Other API stuff: this framework is trying to appeal to a broader audience, so I disliked the "do not use strings/[]bytes returned from it after handler returns" rule because it is more likely to create bugs when passed to libraries that store them long-term.

Instead of this fasthttp behavior, all of the strings returned are copies of the fasthttp version. To compensate for the speed loss, I also added functions like func (c *Ctx) MethodEquals(comparison string) bool that are allocation-free and will cover 80-90% of use cases without sacrificing speed or safety. I will also add "unsafe" equivalents for simple calls (e.g. to databases, marshallers, etc.). Once again, does this feel heavy?

For this framework, I can only pick two of these: speed, syntax, safety. The line is not always clear :)

@valyala
Copy link
Owner

valyala commented Feb 17, 2016

@Anon-Penguin , I'd suggest starting with minimal API providing orthogonal functionality and then adding helper methods for frequently used code.

@ivoviz
Copy link

ivoviz commented Feb 20, 2016

@Anon-Penguin I wouldn't be so concerned about status code typos, we can always use the constants from the package.

@valyala
Copy link
Owner

valyala commented Feb 25, 2016

Just FYI, there is new router with fasthttp support, which is based on ozzo-routing - see https://github.com/qiangxue/fasthttp-routing .

@CaptainCodeman
Copy link

FYI: Labstack Echo V2 supports fasthttp and is already one of, if not the fastest routers / frameworks for the std http lib.

I can highly recommend it as a Go micro framework.

@valyala
Copy link
Owner

valyala commented Mar 5, 2016

@CaptainCodeman , just added Echo v2 into fasthttp's README.md.

@thedrow
Copy link
Author

thedrow commented Mar 6, 2016

@CaptainCodeman Nice. I used Echo before and it's pretty awesome.

@CaptainCodeman
Copy link

To give fasthttp a try I just switched an image service running on AppEngine Managed VMs to use echo + fasthttp + libvips ... seems to be running great!

It's hard to judge performance with so much blob-store loading and caching involved but I'll get a better idea of the impact looking at the overall perf load after a few days.

@valyala
Copy link
Owner

valyala commented Mar 15, 2016

Closing this issue, since certain frameworks already support fasthttp. These frameworks are mentioned in the FAQ. See the question Are there plans to add request routing to fasthttp? there.

@valyala valyala closed this as completed Mar 15, 2016
@ghost
Copy link

ghost commented Apr 12, 2016

Iris supports only fasthttp

Nice job with fasthttp @valyala !

@tsingson
Copy link

great job . thanks for open

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

No branches or pull requests

6 participants