Newer
Older
package main
import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"log"
"math"
"runtime"
"strconv"
"strings"
"time"
// "io/ioutil"
"net/http"
)
//struct for holding the species array in country
type arraySpeciesJSON struct {
ArryJson []speciesJSON2 `json:"results"`
}
//just a small struct used to make it easier to get year
type specisYearJson struct {
Key float64 `json:"key"`
}
//struct for json respnce in country method
type countryJSON struct {
Code string `json:"code"`
Countryname string `json:"countryname"`
CountryFlag string `json:"countryflag"`
Species []speciesJSON2 `json:"species"`
SpeciesKey []specisYearJson `json:"speciesKey"`
}
//due to stupid implementation by me i had to make an identical struct with an float responce in year, hey if it works it works
// the initial json was made when my understanding of json was poor, something that imporved over time, but i am afraid that trying to improve the json
//to the other type might break it
type speciesJSON2 struct {
Key float64 `json:"key"`
Kingdom string `json:"kingdom"`
Phylum string `json:"phylum"`
Order string `json:"order"`
Family string `json:"family"`
Genus string `json:"genus"`
ScientificName string `json:"scientificName"`
CanonicalName string `json:"canonicalName"`
Year float64 `json:"year"`
}
type speciesJSON struct {
Key float64 `json:"key"`
Kingdom string `json:"kingdom"`
Phylum string `json:"phylum"`
Order string `json:"order"`
Family string `json:"family"`
Genus string `json:"genus"`
ScientificName string `json:"scientificName"`
CanonicalName string `json:"canonicalName"`
Year string `json:"year"`
}
//json struct for diagnose
Rescountries int `json:"restcountries"`
Version string `json:"version"`
Uptime float64 `json:"uptime"`
}
StartTime = time.Time{} //for uptime
//filter for url methods
countryFilter = "/conservation/v1/country/"
specisFilter = "/conservation/v1/species/"
diagFilter = "/conservation/v1/diag/"
)
func main() {
//starts the uptime counter
//to handle random / and undefined behavior
//handels the functions based on user input, the 2. parameter is the global string used for filtering
http.HandleFunc(countryFilter, country)
http.HandleFunc(specisFilter, species)
http.HandleFunc(diagFilter, diag)
//tries to get the port from the port number from the env file
//if it is unable to find the port variable it forces one
if port == "" {
port = "8080"
}
//opens and continus listens on said port
log.Fatal(http.ListenAndServe(":"+port, nil))
}
func undefined(w http.ResponseWriter, r *http.Request){
io.WriteString(w, "please use /conservation/v1/country/ /conservation/v1/species/ /conservation/v1/diag/")
}
func country(w http.ResponseWriter, r *http.Request){
var input = r.URL.String() //takes in an raw url string to keep the question mark
filtered := strings.Replace(input,countryFilter, "", -1) //removes the unessesary parts of the url
countryCode := string(filtered[0:2]) //saves away country parameter, its always 2 letters
filterNumber := strings.Replace(filtered,countryCode+"&limit=", "", -1) //removes more of the url to only get the filter number
//makes it possible to not send in an limit, sets the value to 10 if no limit has been given
//it also now doesnt accept negative numbers or letters , default is size is 10 if not proper limit has been given
{
testInt, _ := strconv.Atoi(filterNumber)
if testInt <= 0{
filterNumber = "10"
}
}
resp, err := http.Get("https://restcountries.eu/rest/v2/alpha/"+countryCode) //get full cpountry json responce
if err != nil {
print("error\n")
log.Fatalln(err)
}
{ //
tempLimit, _ :=strconv.Atoi(filterNumber) //checks that the input number is not over 300, the api does not support 300+ in limit
//sets it to 300 if its to big
if tempLimit > 300 {
filterNumber ="300"
}
}
//gets the species part of the json
respSpecis, err := http.Get("http://api.gbif.org/v1/occurrence/search?country="+countryCode+"&"+"limit="+filterNumber)
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
if err != nil {
print("error\n")
log.Fatalln(err)
}
// defer respSpecis.Body.Close()
// bodySpecis, err := ioutil.ReadAll(respSpecis.Body)
// if err != nil {
// print("error\n")
// log.Fatalln(err)
// }
// var infoSpecis map[string]interface{}
// json.Unmarshal([]byte(bodySpecis),&infoSpecis)
// numberResponce := infoSpecis["limit"]
// var intNumberResponce int = int(numberResponce.(float64))
// var countryJsonArray []speciesJSON
/* var objmap map[string]*json.RawMessage
//err = json.Unmarshal(bodySpecis, &objmap)
var s interface{}
err = json.Unmarshal(*objmap["results"], &s)
*/
//err = json.Unmarshal(s[1], &test)
// str := fmt.Sprintf("%v", s)
// var test map[string]interface{}
// io.WriteString(w,string(str))
// str := fmt.Sprintf("%v", respSpecis.Body)
// println(str)
err = json.NewDecoder(respSpecis.Body).Decode(&spectest) //decodes the json into spectest
if err != nil {
print("error\n")
log.Fatalln(err)
}
var countryJsonArray []speciesJSON2
var yearJsonArray []specisYearJson
var duplicateCheck = "" //builds an string with all entires and checks for dupes after
intFilternumber, _ := strconv.Atoi(filterNumber) //go has some werid problems with conversion of types
for i:=0; i<intFilternumber ;i++ {
keyTest := fmt.Sprintf("%f", spectest.ArryJson[i].Key) //gets the key
if strings.Contains(duplicateCheck, keyTest) { //check if key already exists, go out of loop if it does
duplicateCheck += keyTest+","
key := spectest.ArryJson[i].Key
kingdom := spectest.ArryJson[i].Kingdom
phylum := spectest.ArryJson[i].Phylum
order := spectest.ArryJson[i].Order
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
genus := spectest.ArryJson[i].Genus
scientificName := spectest.ArryJson[i].ScientificName
canonicalName := spectest.ArryJson[i].CanonicalName
year := spectest.ArryJson[i].Year
tempJson := speciesJSON2{float64(key),kingdom, phylum,order,family,
genus,scientificName,canonicalName,year}
tempYearJson := specisYearJson{key}
countryJsonArray =append(countryJsonArray,tempJson)
yearJsonArray =append(yearJsonArray,tempYearJson)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
print("error\n")
log.Fatalln(err)
}
var info map[string]interface{} //as mentioned in the start of the document this is my bad implementation of json, but since it works im afraid to fix it properly to the other
//implementation.
tempCode := info["alpha2Code"]
tempCountryname := info["name"]
tempCountryFlag := info["flag"]
//this is so i can collapse this test /
{
if tempCode == nil {
tempCode = "NA"
}
if tempCountryname == nil {
tempCountryname = "NA"
}
if tempCountryFlag == nil {
tempCountryFlag = "NA"
}
}
createdJson := countryJSON{tempCode.(string),tempCountryname.(string),tempCountryFlag.(string),
countryJsonArray,yearJsonArray}
e,err := json.Marshal(createdJson)
// fmt.Fprint(w,(json.MarshalIndent(string(e), "", " ")))
w.Header().Add("content-type", "application/json")
io.WriteString(w,string(e))
}
func species(w http.ResponseWriter, r *http.Request){
//io.WriteString(w, "\nspecies\n\n")
filtred := strings.Replace(input,specisFilter, "", -1) //filter out the paramteter
resp,err := http.Get("http://api.gbif.org/v1/species/"+filtred) //runs api call with that paramter
if resp.StatusCode == 404 {
io.WriteString(w,"404") //if input is invalid we do an 404 check and writes that out on the page if that is the case
if err != nil {
print("error\n")
log.Fatalln(err)
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
print("error\n")
log.Fatalln(err)
}
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
var info map[string]interface{} //this is an shit way of doing json, it works for easier structures but not with nested, which is the reasons i go away from it later on
json.Unmarshal([]byte(body), &info)
tempKey := info["key"]
tempNameKey := info["nameKey"]
tempKingdom := info["kingdom"]
tempPhylum := info["phylum"]
tempOrder := info["order"]
tempFamily := info["family"]
tempGenus := info["genus"]
tempScientificName := info["scientificName"]
tempCanonicalName := info["canonicalName"]
var namekeyInt int = int(tempNameKey.(float64))
//this is so i can collapse this test
{
if tempKey == nil {
tempKey = "NA"
}
if tempKingdom == nil {
tempKingdom = "NA"
}
if tempPhylum == nil {
tempPhylum = "NA"
}
if tempFamily == nil {
tempFamily = "NA"
}
if tempGenus == nil {
tempGenus = "NA"
}
if tempScientificName == nil {
tempScientificName = "NA"
}
if tempCanonicalName == nil {
tempCanonicalName = "NA"
}
if namekeyInt == 0 {
namekeyInt = 0
}
respYear, err := http.Get("http://api.gbif.org/v1/species/" + strconv.Itoa(namekeyInt) + "/name") //uses the namekey from the species call to find year in /name
if err != nil {
print("error\n")
log.Fatalln(err)
defer respYear.Body.Close()
bodyYear, err := ioutil.ReadAll(respYear.Body)
if err != nil {
print("error\n")
log.Fatalln(err)
}
var infoYear map[string]interface{}
json.Unmarshal([]byte(bodyYear), &infoYear) //again this poor implementation of json, but it works
tempYear := infoYear["year"]
createdJson := speciesJSON{tempKey.(float64), tempKingdom.(string), tempPhylum.(string), tempOrder.(string), tempFamily.(string),
tempGenus.(string), tempScientificName.(string), tempCanonicalName.(string), tempYear.(string)}
e, err := json.Marshal(createdJson)
w.Header().Add("content-type", "application/json")
io.WriteString(w, string(e))
func diag(w http.ResponseWriter, r *http.Request){
gbifCode := 0 //variable to hold responce code from gbif api
rescountriesCode := 0 //variable to hold responce code from restcountries api
version := runtime.Version() //get current go version
serverRuntime := time.Since(StartTime).Seconds() //global variable introdused, it starts counting when main is ran, and calculates time since that happend
serverRuntime = math.Round(serverRuntime*100)/100 //makes it into secounds with 2 decimales, change the rounding to make it into pure secounds. i prefered it with 2 decimales
/*
* this test does a empty get request to the gbif api main page, and based on the responce saves the responce code
* if the site is unreachable the status code is sat to 503 (service unaviable)
*/
respGbif,err := http.Get("http://api.gbif.org/")
if respGbif == nil {
gbifCode = 503
}else{
if err != nil{
gbifCode = respGbif.StatusCode
}else{
gbifCode = respGbif.StatusCode
}
}
/*
* this test does a empty get request to the respRestcountries api main page, and based on the responce saves the responce code
* if the site is unreachable the status code is sat to 503 (service unaviable)
*/
respRestcountries,err := http.Get("http://restcountries.eu/")
if respRestcountries == nil {
rescountriesCode = 503
}else {
if err != nil{
rescountriesCode = respRestcountries.StatusCode
}else{
rescountriesCode = respRestcountries.StatusCode
// creates an json bassed on the variables above
createdJson := diagJSON{gbifCode,rescountriesCode,version,serverRuntime}
e,err := json.Marshal(createdJson)
if err != nil {
print("error\n")
log.Fatalln(err)
//sets the content type to json to make prettier output
w.Header().Add("content-type", "application/json")
//outputs the json to screen
io.WriteString(w,string(e))
}
func fouroFour(w http.ResponseWriter, r *http.Request){