package main import ( "bytes" "encoding/json" "errors" "fmt" "io" "io/ioutil" "log" "net/http" "os" "os/exec" "path/filepath" "strings" "github.com/getkin/kin-openapi/openapi3" ) type PublicAPI struct { Name string `json:"name"` Category string `json:"category,omitempty"` Description string `json:"description"` Icon string `json:"icon,omitempty"` OpenAPIJson string `json:"open_api_json"` Pricing map[string]int64 `json:"pricing,omitempty"` ExamplesJson string `json:"examples_json,omitempty"` PostmanJson string `json:"postman_json,omitempty"` DisplayName string `json:"display_name,omitempty"` } func publishAPI(apiSpec *PublicAPI) error { client := &http.Client{} //Encode the data postBody, _ := json.Marshal(map[string]interface{}{ "api": apiSpec, }) rbody := bytes.NewBuffer(postBody) //Leverage Go's HTTP Post function to make request req, err := http.NewRequest("POST", "https://api.m3o.com/publicapi/Publish", rbody) // Add auth headers here if needed req.Header.Add("Authorization", `Bearer `+os.Getenv("MICRO_ADMIN_TOKEN")) resp, err := client.Do(req) if err != nil { return err } defer resp.Body.Close() if resp.StatusCode != 200 { b, _ := ioutil.ReadAll(resp.Body) return errors.New(string(b)) } io.Copy(ioutil.Discard, resp.Body) return nil } func main() { files, err := ioutil.ReadDir(os.Args[1]) if err != nil { log.Fatal(err) } workDir, _ := os.Getwd() for _, f := range files { if strings.Contains(f.Name(), "clients") || strings.Contains(f.Name(), "examples") { continue } if f.IsDir() && !strings.HasPrefix(f.Name(), ".") { serviceDir := filepath.Join(workDir, f.Name()) serviceFiles, err := ioutil.ReadDir(serviceDir) if err != nil { fmt.Println("Failed to read service dir", err) os.Exit(1) } skip := false for _, serviceFile := range serviceFiles { if serviceFile.Name() == "skip" { skip = true } } if skip { continue } fmt.Println("Processing folder", serviceDir) makeProto := exec.Command("make", "api") makeProto.Dir = serviceDir fmt.Println(serviceDir) outp, err := makeProto.CombinedOutput() if err != nil { fmt.Println("Failed to make api", string(outp)) os.Exit(1) } serviceName := f.Name() // generate the Postman collection postman := exec.Command("openapi2postmanv2", "-s", fmt.Sprintf("api-%s.json", serviceName), "-o", "postman.json") postman.Dir = serviceDir outp, err = postman.CombinedOutput() if err != nil { fmt.Printf("Failed to generate postman collection %s %s\n", string(outp), err) os.Exit(1) } dat, err := ioutil.ReadFile(filepath.Join(serviceDir, "README.md")) if err != nil { fmt.Println("Failed to read readme", string(outp)) os.Exit(1) } apiJSON := filepath.Join(serviceDir, "api-"+serviceName+".json") js, err := ioutil.ReadFile(apiJSON) if err != nil { apiJSON := filepath.Join(serviceDir, "api-protobuf.json") js, err = ioutil.ReadFile(apiJSON) if err != nil { fmt.Println("Failed to read json spec", err) os.Exit(1) } } spec := &openapi3.Swagger{} // we have to read an openapi spec otherwise we can't publish if err := json.Unmarshal(js, &spec); err != nil { fmt.Println("Failed to unmarshal", err) os.Exit(1) } // define the default public api values publicApi := new(PublicAPI) // if we find a public api definition we load it if b, err := ioutil.ReadFile(filepath.Join(serviceDir, "publicapi.json")); err == nil { // unpack the info if we read the file json.Unmarshal(b, &publicApi) } // If we didn't get the default info from a file, populate it if publicApi.Name == "" { publicApi.Name = serviceName } if publicApi.Description == "" { publicApi.Description = string(dat) } if publicApi.OpenAPIJson == "" { publicApi.OpenAPIJson = string(js) } // load the examples if they exist if examples, err := ioutil.ReadFile(filepath.Join(serviceDir, "examples.json")); err == nil { if len(examples) > 0 { publicApi.ExamplesJson = string(examples) } } // load the separate pricing if it exists if pricingRaw, err := ioutil.ReadFile(filepath.Join(serviceDir, "pricing.json")); err == nil { pricing := map[string]int64{} // unmarshal the pricing info if len(pricingRaw) > 0 { json.Unmarshal(pricingRaw, &pricing) publicApi.Pricing = pricing } } // load the postman json if postman, err := ioutil.ReadFile(filepath.Join(serviceDir, "postman.json")); err == nil { if len(postman) > 0 { publicApi.PostmanJson = string(postman) } } // publish the api if err := publishAPI(publicApi); err != nil { fmt.Println("Failed to save data to publicapi service", err) os.Exit(1) } } } }