Giter VIP home page Giter VIP logo

yaag's Introduction

Build Status

Trello Board

YAAG : Yet Another API doc Generator

Golang is awesome for developing web apps. And people have created a bunch of awesome Web-Frameworks, Web helper libraries. If we consider the entire ecosystem of web apps in Golang everything except API documentation seems to be in place. So we have created the first API doc generator for Golang based web apps and calling it Yet another.

Why ?

Most of the web services expose their APIs to the mobile or third party developers. Documenting them is somewhat pain in the ass. We are trying to reduce the pain, at least for in house projects where you don't have to expose your documentation to the world. YAAG generates simple bootstrap based API documentation without writing a single line of comments.

How it works ?

YAAG is a middleware. You have to add YAAG handler in your routes and you are done. Just go on calling your APIs using POSTMAN, Curl or from any client, and YAAG will keep on updating the API Doc html. (Note: We are also generating a json file containing data af all API calls)

How to use with basic net.http package

  1. Import github.com/betacraft/yaag/yaag
  2. Import github.com/betacraft/yaag/middleware
  3. Initialize yaag yaag.Init(&yaag.Config{On: true, DocTitle: "Core", DocPath: "apidoc.html"})
  4. Use it in your handlers as http.HandleFunc("/", middleware.HandleFunc(handler))

Sample code

func handler(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
}

func main() {
  yaag.Init(&yaag.Config{On: true, DocTitle: "Core", DocPath: "apidoc.html", BaseUrls : map[string]string{"Production":"","Staging":""} })
  http.HandleFunc("/", middleware.HandleFunc(handler))
  http.ListenAndServe(":8080", nil)
}

How to use with Gorilla Mux

  1. Import github.com/betacraft/yaag/yaag
  2. Import github.com/betacraft/yaag/middleware
  3. Initialize yaag yaag.Init(&yaag.Config{On: true, DocTitle: "Gorilla Mux", DocPath: "apidoc.html"})
  4. Use it in your handlers as r.HandleFunc("/", middleware.HandleFunc(handler))

Sample code

func handler(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintf(w, time.Now().String())
}

func main() {
  yaag.Init(&yaag.Config{On: true, DocTitle: "Gorilla Mux", DocPath: "apidoc.html"})
  r := mux.NewRouter()
  r.HandleFunc("/", middleware.HandleFunc(handler)) 
  http.ListenAndServe(":8080", r)
}

How to use with Martini

  1. Import github.com/betacraft/yaag/yaag
  2. Import github.com/betacraft/yaag/martiniyaag
  3. Initialize yaag yaag.Init(&yaag.Config{On: true, DocTitle: "Martini", DocPath: "apidoc.html"})
  4. Add Yaag middleware like m.Use(martiniyaag.Document)

Sample Code

func main() {
  yaag.Init(&yaag.Config{On: true, DocTitle: "Martini", DocPath: "apidoc.html"})
  m := martini.Classic()
  m.Use(martiniyaag.Document)
  m.Get("/", func() string {
    return "Hello world!"
  })
  m.Run()
}

How to use with Revel

  1. Add yaag.record = true in conf/app.conf (before starting to record the api calls)
  2. import github.com/betacraft/yaag/filters in app/init.go
  3. add 'filters.FilterForApiDoc' in revel.Filters
  4. Start recording Api calls

Sample Code

func init() {
	// Filters is the default set of global filters.
	revel.Filters = []revel.Filter{
		filters.FilterForApiDoc,       // This enables yaag to record apicalls
		revel.PanicFilter,             // Recover from panics and display an error page instead.
		revel.RouterFilter,            // Use the routing table to select the right Action
		revel.FilterConfiguringFilter, // A hook for adding or removing per-Action filters.
		revel.ParamsFilter,            // Parse parameters into Controller.Params.
		revel.SessionFilter,           // Restore and write the session cookie.
		revel.FlashFilter,             // Restore and write the flash cookie.
		revel.ValidationFilter,        // Restore kept validation errors and save new ones from cookie.
		revel.I18nFilter,              // Resolve the requested language
		HeaderFilter,                  // Add some security based headers
		revel.InterceptorFilter,       // Run interceptors around the action.
		revel.CompressFilter,          // Compress the result.
		revel.ActionInvoker,           // Invoke the action.
	}

	revel.OnAppStart(func() {
		yaag.Init(&yaag.Config{ // <- IMPORTANT, init the middleware.
			On:       true,
			DocTitle: "Revel",
			DocPath:  "examples/revel/apidoc.html",
			BaseUrls: map[string]string{"Production": "", "Staging": ""},
		})
	})
}

How to use with Gin

  1. Import github.com/betacraft/yaag/yaag
  2. Import github.com/betacraft/yaag/gin
  3. Initialize yaag yaag.Init(&yaag.Config(On: true, DocTile: "Gin", DocPath: "apidpc.html"))
  4. Add yaag middleware like r.User(yaag_gin.Document())

Sample Code

import (
    "net/http"
    yaag_gin "github.com/betacraft/yaag/gin/v1"
    "github.com/betacraft/yaag/yaag"
    "gopkg.in/gin-gonic/gin.v1"
    )
func main() {
    r := gin.Default()
    yaag.Init(&yaag.Config{On: true, DocTitle: "Gin", DocPath: "apidoc.html", BaseUrls: map[string]string{"Production": "", "Staging": ""}})
    r.Use(yaag_gin.Document())
    // use other middlewares ...
    r.GET("/", func(c *gin.Context) {
        c.String(http.StatusOK, "Hello World!")
    })
    r.Run(":8080")
}

Using github for gin dependency

import (
    "net/http"
    yaag_gin "github.com/betacraft/yaag/gin"
    "github.com/betacraft/yaag/yaag"
    "github.com/gin-gonic/gin"
    )
func main() {
    r := gin.Default()
    yaag.Init(&yaag.Config{On: true, DocTitle: "Gin", DocPath: "apidoc.html", BaseUrls: map[string]string{"Production": "", "Staging": ""}})
    r.Use(yaag_gin.Document())
    // use other middlewares ...
    r.GET("/", func(c *gin.Context) {
        c.String(http.StatusOK, "Hello World!")
    })
    r.Run(":8080")
}

How to use with Iris

  1. Import github.com/betacraft/yaag/yaag
  2. Import github.com/betacraft/yaag/irisyaag
  3. Initialize yaag yaag.Init(&yaag.Config(On: true, DocTile: "Iris", DocPath: "apidoc.html"))
  4. Register yaag middleware like app.Use(irisyaag.New())

irisyaag records the response body and provides all the necessary information to the apidoc.

Sample Code

package main

import (
  "github.com/kataras/iris"
  "github.com/kataras/iris/context"

  "github.com/betacraft/yaag/irisyaag"
  "github.com/betacraft/yaag/yaag"
)

type myXML struct {
  Result string `xml:"result"`
}

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

  yaag.Init(&yaag.Config{ // <- IMPORTANT, init the middleware.
    On:       true,
    DocTitle: "Iris",
    DocPath:  "apidoc.html",
    BaseUrls: map[string]string{"Production": "", "Staging": ""},
  })
  app.Use(irisyaag.New()) // <- IMPORTANT, register the middleware.

  app.Get("/json", func(ctx context.Context) {
    ctx.JSON(context.Map{"result": "Hello World!"})
  })

  app.Get("/plain", func(ctx context.Context) {
    ctx.Text("Hello World!")
  })

  app.Get("/xml", func(ctx context.Context) {
    ctx.XML(myXML{Result: "Hello World!"})
  })

  app.Get("/complex", func(ctx context.Context) {
    value := ctx.URLParam("key")
    ctx.JSON(iris.Map{"value": value})
  })

  // Run our HTTP Server.
  //
  // Note that on each incoming request the yaag will generate and update the "apidoc.html".
  // Recommentation:
  // Write tests that calls those handlers, save the generated "apidoc.html".
  // Turn off the yaag middleware when in production.
  //
  // Example usage:
  // Visit all paths and open the generated "apidoc.html" file to see the API's automated docs.
  app.Run(iris.Addr(":8080"))
}

How to use with httprouter package

  1. Import github.com/betacraft/yaag/yaag
  2. Import github.com/betacraft/yaag/httprouteryaag
  3. Initialize yaag yaag.Init(&yaag.Config{On: true, DocTitle: "Httprouter", DocPath: "apidoc.html"})
  4. Use it in your handlers as router.Handle("GET", "/", httprouteryaag.HandleFunc(handler))

Sample code

func handler(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
  fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
}

func main() {
  yaag.Init(&yaag.Config{On: true, DocTitle: "Httprouter", DocPath: "apidoc.html", BaseUrls : map[string]string{"Production":"","Staging":""} })
  router := httprouter.New()
  router.Handle("GET", "/", httprouteryaag.HandleFunc(handler))
  http.ListenAndServe(":8080", router)
}

Screenshots

API doc is generated based on the paths

alt first

Click on any call to see the details of the API

alt second

Screencast

YAAG ScreenCast

Contributors

This project is initiated by Betacraft during GopherGala 2015.

yaag's People

Contributors

abhi11 avatar akshaydeo avatar aniketawati avatar briannewsom avatar dependabot[bot] avatar gie777 avatar hiveminded avatar hostirosti avatar jamesnaw avatar jpetitcolas avatar kataras avatar leandromoreira avatar ryan-git avatar sdkie avatar zdebra avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

yaag's Issues

Documentations for 3xx and 4xx is needed.

Hi,

I have been using yagg for generating the API documentation. I found API are generating only for success cases. I have found this piece of code. Here you are allowing only for status codes ranges in 2XX.

func IsStatusCodeValid(code int) bool  {
	if code >= 200 && code < 300 {
		return true
	} else {
		return false
	}
}

please rewrite it to allow 3xx and 4xx

not able to use it with gin !

cannot use "github.com/betacraft/yaag/gin".Document() (type "gopkg.in/gin-gonic/gin.v1".HandlerFunc) as type "github.com/gin-gonic/gin".HandlerFunc in argument to router.Use

hi,I have a problem with "go mod" .

require github.com/betacraft/yaag/yaag: version "v0.0.0-20191027021412-565f65e36090" invalid: missing github.com/betacraft/yaag/yaag/go.mod at revision 565f65e

go.mod:

github.com/betacraft/yaag/yaag master

func generateHtml can't work

func Init(conf *Config) {
	config = conf
	// load the config file
	if conf.DocPath == "" {
		conf.DocPath = "apidoc.html"
	}


	filePath, err := filepath.Abs(conf.DocPath + ".json")
	dataFile, err := os.Open(filePath)
	defer dataFile.Close()
	if err == nil {
		json.NewDecoder(io.Reader(dataFile)).Decode(spec)
		generateHtml()
	}
} 

when init , filePath does not exist os.Open() will be error

err != nil

generateHtml don‘t work always

how do i generateHtml

thanks

Request body is not considered while generating document in unit test mode.

I have integrated yaag with iris application, when this app is run in production or live server then the Post Request body is considered and included in generated document. But when we run unit tests with httptest then Request Body is ignored in generated documents.

The below pull request is required to test this.
#34

cannot use irisyaag.New()

cannot use irisyaag.New() (type "github.com/kataras/iris/context".Handler) as type "github.com/kataras/iris/v12/context".Handler in argument to api.APIBuilder.Use

Hangs when I run `go get`

There seems to be a 404 when I run go get using

yaag_gin "github.com/betacraft/yaag/gin"
    "github.com/betacraft/yaag/yaag"

Importing gin-gonic/gin.v1

I import the versioned gin framework and its causing I think its causing problems. Any ideas on how to fix?

cannot use "github.com/betacraft/yaag/gin".Document() (type "github.com/gin-gonic/gin".HandlerFunc) as type "placeable.com/audit-service/vendor/gopkg.in/gin-gonic/gin.v1".HandlerFunc in argument to r.Use

Add support for editing API other fields

First of all, it is really convenient to generate api documents in this way, there is really no pain. But there are some limitations.

For example, API description, param description cannot be customized.

If you can continue to edit the api description and parameter description in the generated html file, then this tool can be safely used in many project

some idea:

  • Integration with other online document editing services
  • Adapt the generated data to tools such as swagger or apidoc

Implementing yaag into existing project

I currently have a moderately sized API that is in ongoing development and I came across your "yaag" project and thought I would give it a whirl. I checked out our martini branch and started implementing as your README.md dictates.

I made sure to import the two yaag libraries: yaag/yaag and yaag/martiniyaag

Added: m.Use(martiniyaag.Document)

I now have so many damn m.Use statements it is getting out of control ;)

That seems to be all that is necessary other than initiating the config option in my main(), which I did as well. Do you know if utilizing route groups with Martini would prevent this from working as expected? Currently I leverage m.Group() for all of our routes.

Use the wrong repo path in readme file

The repo path should be :

"github.com/RainingClouds/yaag/martiniyaag"
"github.com/RainingClouds/yaag/yaag"

But the below path appear in readme file:

Import github.com/gophergala/yaag/yaag
Import github.com/gophergala/yaag/martiniyaag

I'm not getting any output

I've initialised the library...

yaag.Init(&yaag.Config{
        On:       true,
        DocTitle: "Gin",
        DocPath:  "apidoc.html",
        BaseUrls: map[string]string{"Production": "http://api.test.com", "Staging": "http://devapi.test.com"},
    })

But I'm not getting any output, no apidoc.html file's being recreated etc

Am I missing something?

Cheers!

Handle multipart/form-data POSTs

When I post multipart/form-data, Yaag doesn't give me the form data. I think we should ignore the file data, but parse the data and show it for simpler documentation.

For example, this post had json data included with it:
screenshot 2016-01-26 at 10 14 36 am

Thanks!

Allow for configurable template

If you're exposing API docs to third parties, you probably want the ability to have the docs at least somewhat match the look and feel of the rest of your site.

websocket: response does not implement http.Hijacker

Getting an error when I use websockets with yaag middleware.

func echo(w http.ResponseWriter, r *http.Request) {
	c, err := upgrader.Upgrade(w, r, nil)
	hErr(err, "upgrade err")
	defer c.Close()
	for {
		// c.ReadJSON()
		mt, message, err := c.ReadMessage()
		hErr(err, "readMessage")
		hErr(c.WriteMessage(mt, message), "write err")
	}
}

The error happens at the upgrader.Upgrade() call

Adding native support for bmizerany/pat (Sinatra style pattern muxer)

How much work would it be to add native support for https://github.com/bmizerany/pat (a Sinatra style pattern muxer)? It's built purely on "net/http" and "net/url", so there might be a workaround that leverages the basic net.http package (https://github.com/betacraft/yaag#how-to-use-with-basic-nethttp-package), but I figured I would ask about native support.

By the way, thank you for creating this project! This sort of middleware-based api doc generation is extremely useful for large projects with constantly evolving handlers.

can I add extra information with annotations?

I would like to add additional information to the template using some annotations over the functions handlers, something like

@Description  This endpoint to get all the users in the app
@return json
@... 
func getAllUsers(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
}

And handle the route

r.GET("/api/v1/users/all", getAllUsers) 

And generate something like

This endpoint to get all the users in the app
GET: /api/v1/users/all

can I do that?

Help with Negroni / Gorilla Mux combination

Can anyone help getting Yaag to work with Negroni and Gorilla Mux? No matter what I try I seem to get nothing or I get mulitple http write errors probably because because I already have routes.

I have tried this and a few other things ...
`
yaag.Init(&yaag.Config{On: true, DocTitle: "Negroni-gorilla", DocPath: "apidoc.html", BaseUrls: map[string]string{"Production": "", "Staging": ""}})

router := mux.NewRouter()
// ... Add a bunch of routes
router.HandleFunc("/", middleware.HandleFunc(handler)) //this does nothing
n := negroni.Classic()
n.Use(c)
//n.UseHandlerFunc(middleware.HandleFunc(handler)) //this gives an error but makes a doc
n.UseHandler(router)
n.Run(":5000")

func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, time.Now().String())

}

`

Update:
I got "n.UseHandlerFunc(middleware.HandleFunc(handler))" to work by removing
"fmt.Fprintf(w, time.Now().String())" from the handler. It looks like once I write a response it finishes.
Not sure if that is really working or not.
I still don't get responses. Just requests.

Another_ question (if the first question can be solved):
All the examples show just returning time. How do you return the actual response?
Maybe this would become more apparent if this was working for me. But it seems like all the handlers just return time. Help my Ignorance. Are the responses generated in the middleware somehow?
I know we could return something else in the handler but I don't see how to return a response.

application/x-www-form-urlencoded 参数为空时报错

application/x-www-form-urlencoded 参数为空时报错

INFO] 2019/09/08 12:16 200 3.582027ms 127.0.0.1 POST /m/login
12:18:23 app | 2019/09/08 12:18:23 application/x-www-form-urlencoded
12:18:23 app | 2019/09/08 12:18:23 Reading form
12:18:23 app | [WARN] 2019/09/08 12:18 Recovered from a route's Handler('github.com/betacraft/yaag/irisyaag.New.func1')
At Request: 200 /m/login POST 127.0.0.1
Trace: runtime error: index out of range

/usr/local/Cellar/go/1.12.9/libexec/src/runtime/panic.go:522
/usr/local/Cellar/go/1.12.9/libexec/src/runtime/panic.go:44
/Users/xxx/go/src/github.com/betacraft/yaag/middleware/yaagmiddleware.go:139
/Users/xxx/go/src/github.com/betacraft/yaag/middleware/yaagmiddleware.go:83
/Users/xxx/go/src/github.com/betacraft/yaag/irisyaag/middleware.go:23

/Users/xxx/go/src/github.com/betacraft/yaag/middleware/yaagmiddleware.go:139
func ReadPostForm(req *http.Request) map[string]string {
postForm := map[string]string{}
for _, param := range strings.Split(*ReadBody(req), "&") {
value := strings.Split(param, "=")
postForm[value[0]] = value[1]
}
return postForm
}

加粗这一行,很明显没有判断空参数的情况。

cpu, Memory usage spike when endpoints returns a large json file

We got cpu, memory and file descriptors spikes when the endpoint returns a large json object. pprof shows most of them are spent on yaag/yaag.GenerateHtml and yaag/yaag.Init. Down the tree it, it calls encoding/json.Mashal (47%) and html/template.htmlReplacer(34%) which calls runtime.slicebytetostring(16%) and bytes.(*Buffer).WriteString.

The memory doesn't get GC-ed quickly.

Why not follow Swagger standard?

Can yaag configure to follow Swagger/OpenAPI standard as it can import by Postman and do automated testing?

Can anyone recommend an existing solution?

Vet issues

Running go vet:

akshay@storm:$ go vet github.com/betacraft/yaag/yaag
../../github.com/betacraft/yaag/yaag/yaag.go:111: unreachable code
../../github.com/betacraft/yaag/yaag/yaag.go:117: unreachable code
exit status 1

Cannot install the package

I have the following errors when I execute go get github.com/betacraft/yaag/..

#github.com/betacraft/yaag/filters
../github.com/betacraft/yaag/filters/filter.go:24:32: cannot use w (type *httptest.ResponseRecorder) as type revel.ServerResponse in argument to revel.NewResponse:
*httptest.ResponseRecorder does not implement revel.ServerResponse (missing Get method)
../github.com/betacraft/yaag/filters/filter.go:30:22: c.Request.Request undefined (type *revel.Request has no field or method Request)
../github.com/betacraft/yaag/filters/filter.go:35:39: c.Request.Request undefined (type *revel.Request has no field or method Request)
../github.com/betacraft/yaag/filters/filter.go:81:14: cannot range over c.Request.Header (type *revel.RevelHeader)

I'm using go version go1.9.2 darwin/amd64

yaag sometimes it doesn't work

When I request the server,sometimes yaag add the api info to apidoc.html,but sometines it doesn't work;
My computer environment is windows

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.