Skip to content
Snippets Groups Projects
Commit 31d838b9 authored by Benjamin skinstad's avatar Benjamin skinstad
Browse files

cleaned up the code and expanded on documentation

parent e50afcb1
No related branches found
No related tags found
No related merge requests found
module awesomeProject
go 1.13
......@@ -17,16 +17,18 @@ import (
"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"`
......@@ -36,6 +38,10 @@ type countryJSON struct {
}
//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"`
......@@ -60,16 +66,20 @@ type speciesJSON struct {
Year string `json:"year"`
}
//json struct for diagnose
type diagJSON struct {
Gbif int `json:"gbif"`
Rescountries int `json:"rescountries"`
Rescountries int `json:"restcountries"`
Version string `json:"version"`
Uptime float64 `json:"uptime"`
}
//global variables
var(
StartTime = time.Time{}
StartTime = time.Time{} //for uptime
//filter for url methods
countryFilter = "/conservation/v1/country/"
specisFilter = "/conservation/v1/species/"
diagFilter = "/conservation/v1/diag/"
......@@ -79,40 +89,27 @@ var(
func main() {
/*fiks limit
finn ut om vi trenger å lage en json //ja, desverre
lag riktig json for country/specis/diag
inkluder år i species
finn ut hvordan man finner diag informationen //ping something
inkluder specis i country
remove dupes
//optional
add error code handinling
add custom 404
add rate limiting
startTime := time.Now()
*/
// add switch here
//starts the uptime counter
StartTime = time.Now()
//to handle random / and undefined behavior
http.HandleFunc("/", undefined)
//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
port := os.Getenv("PORT")
//if it is unable to find the port variable it forces one
if port == "" {
port = "8080"
}
println(port)
//opens and continus listens on said port
log.Fatal(http.ListenAndServe(":"+port, nil))
......@@ -121,36 +118,50 @@ func main() {
func undefined(w http.ResponseWriter, r *http.Request){
io.WriteString(w, "please use /country,/species,/diag ")
io.WriteString(w, "please use /conservation/v1/country/ /conservation/v1/species/ /conservation/v1/diag/")
}
func country(w http.ResponseWriter, r *http.Request){
//io.WriteString(w, "\ncountry\n\n")
fmt.Fprint(w, "\nCountry\n\n")
var input = r.URL.String()
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
filtered := strings.Replace(input,countryFilter, "", -1)
countryCode := string(filtered[0:2])
filterNumber := strings.Replace(filtered,countryCode+"&limit=", "", -1) //removes more of the url to only get the filter number
filterNumber := strings.Replace(filtered,"?limit=", "", -1)
filterNumber = filterNumber[:]
//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"
}
}
// limit := filterNumber // TODO add number check here
tempLimit := 10
resp, err := http.Get("https://restcountries.eu/rest/v2/alpha/"+countryCode)
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)
}
respSpecis, err := http.Get("http://api.gbif.org/v1/occurrence/search?country="+countryCode+"&"+"limit="+strconv.Itoa(tempLimit))
{ //
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)
if err != nil {
print("error\n")
log.Fatalln(err)
......@@ -204,10 +215,13 @@ func country(w http.ResponseWriter, r *http.Request){
// str := fmt.Sprintf("%v", respSpecis.Body)
// println(str)
var spectest arraySpeciesJSON
err = json.NewDecoder(respSpecis.Body).Decode(&spectest)
err = json.NewDecoder(respSpecis.Body).Decode(&spectest) //decodes the json into spectest
if err != nil {
print("error\n")
......@@ -217,19 +231,22 @@ func country(w http.ResponseWriter, r *http.Request){
var countryJsonArray []speciesJSON2
var yearJsonArray []specisYearJson
var duplicateCheck = ""
var duplicateCheck = "" //builds an string with all entires and checks for dupes after
for i:=0; i<tempLimit ;i++ {
intFilternumber, _ := strconv.Atoi(filterNumber) //go has some werid problems with conversion of types
keyTest := fmt.Sprintf("%f", spectest.ArryJson[i].Key)
println(keyTest)
if strings.Contains(duplicateCheck, keyTest) {
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
continue
}
duplicateCheck += keyTest
duplicateCheck += keyTest+","
key := spectest.ArryJson[i].Key
......@@ -257,15 +274,7 @@ func country(w http.ResponseWriter, r *http.Request){
for index, element := range countryJsonArray{
fmt.Println(index, "=>", element)
}
if err != nil {
print("error\n")
log.Fatalln(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
......@@ -276,27 +285,21 @@ func country(w http.ResponseWriter, r *http.Request){
}
var info map[string]interface{}
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.
json.Unmarshal([]byte(body),&info)
//initalises temp variables and set their default values incase something goes wrong
//todo make this work properly
/* tempCode := "error, unable to locate code"
tempCountryname := "error, unable to locate countryname"
tempCountryFlag := "error, unable to locate countryflag"
tempSpecies := "error, unable to locate specis"
tempSpeciesKey := "error, unable to locate specis key"
*/
tempCode := info["alpha2Code"]
tempCountryname := info["name"]
tempCountryFlag := info["flag"]
//tempSpecies := "work in progress " //todo
//tempSpeciesKey := "work in progress " //todo
//this is so i can collapse this test //todo fix species and key test
//this is so i can collapse this test /
{
if tempCode == nil {
tempCode = "NA"
......@@ -321,149 +324,191 @@ func country(w http.ResponseWriter, r *http.Request){
// 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")
//io.WriteString(w, "\nspecies\n\n")
var input = r.URL.Path[:]
filtred := strings.Replace(input,specisFilter, "", -1)
filtred := strings.Replace(input,specisFilter, "", -1) //filter out the paramteter
resp,err := http.Get("http://api.gbif.org/v1/species/"+filtred)
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)
}else {
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
print("error\n")
log.Fatalln(err)
if err != nil {
print("error\n")
log.Fatalln(err)
}
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
var info map[string]interface{}
json.Unmarshal([]byte(body),&info)
if err != nil {
print("error\n")
log.Fatalln(err)
}
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
}
}
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"]
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)
//this is so i can collapse this test //todo fix year 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"
}
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"]
var namekeyInt int = int(tempNameKey.(float64))
createdJson := speciesJSON{tempKey.(float64), tempKingdom.(string), tempPhylum.(string), tempOrder.(string), tempFamily.(string),
tempGenus.(string), tempScientificName.(string), tempCanonicalName.(string), tempYear.(string)}
respYear,err := http.Get("http://api.gbif.org/v1/species/"+strconv.Itoa(namekeyInt)+"/name")
if err != nil {
print("error\n")
log.Fatalln(err)
e, err := json.Marshal(createdJson)
w.Header().Add("content-type", "application/json")
io.WriteString(w, string(e))
}
}
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)
func diag(w http.ResponseWriter, r *http.Request){
tempYear :=infoYear["year"]
fmt.Println(tempYear)
gbifCode := 0 //variable to hold responce code from gbif api
rescountriesCode := 0 //variable to hold responce code from restcountries api
//todo add year check
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
createdJson := speciesJSON{tempKey.(float64),tempKingdom.(string), tempPhylum.(string), tempOrder.(string),tempFamily.(string),
tempGenus.(string),tempScientificName.(string),tempCanonicalName.(string), tempYear.(string)}
/*
* 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
}
}
e,err := json.Marshal(createdJson)
/*
* 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/")
io.WriteString(w,string(e))
}
if respRestcountries == nil {
rescountriesCode = 503
}else {
if err != nil{
rescountriesCode = respRestcountries.StatusCode
}else{
rescountriesCode = respRestcountries.StatusCode
}
}
func diag(w http.ResponseWriter, r *http.Request){
// creates an json bassed on the variables above
createdJson := diagJSON{gbifCode,rescountriesCode,version,serverRuntime}
gbifCode := 0
rescountriesCode := 0
version := runtime.Version()
serverRuntime := time.Since(StartTime).Seconds() //todo fix
serverRuntime = math.Round(serverRuntime*100)/100
respGbif,err := http.Get("http://api.gbif.org/")
if err != nil{
println(err.Error())
}else{
gbifCode = respGbif.StatusCode
}
respRestcountries,err := http.Get("http://restcountries.eu/")
if err != nil{
println(err.Error())
}else{
rescountriesCode = respRestcountries.StatusCode
e,err := json.Marshal(createdJson)
if err != nil {
print("error\n")
log.Fatalln(err)
}
createdJson := diagJSON{gbifCode,rescountriesCode,version,serverRuntime}
//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))
e,err := json.Marshal(createdJson)
}
func fouroFour(w http.ResponseWriter, r *http.Request){
e := "404"
io.WriteString(w,string(e))
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment