git.0x0001f346.de/andreas/api integration
This commit is contained in:
parent
7f0cb3d1ce
commit
16eaba69c4
@ -5,7 +5,7 @@ As a fan of [TimeAPI.io](https://www.timeapi.io/swagger/index.html), but not thi
|
||||
## Usage
|
||||
|
||||
```shell
|
||||
neo@matrix:~$ curl -s -H "Accept: application/json" "http://localhost:9100/Europe/Berlin" | jq
|
||||
neo@matrix:~$ curl -s -H "Accept: application/json" "http://localhost:9100/Time/current/zone?timeZone=Europe/Berlin" | jq
|
||||
{
|
||||
"year": 2023,
|
||||
"month": 6,
|
||||
|
140
apiTime/api.go
Normal file
140
apiTime/api.go
Normal file
@ -0,0 +1,140 @@
|
||||
package apiTime
|
||||
|
||||
import "git.0x0001f346.de/andreas/api"
|
||||
|
||||
var tags []string = []string{"Time"}
|
||||
|
||||
func GetComponents() *api.Components {
|
||||
components := &api.Components{
|
||||
Schemas: map[string]*api.ComponentsSchema{
|
||||
"CurrentTime": {
|
||||
Properties: map[string]*api.ComponentsProperty{
|
||||
"year": {
|
||||
Type: "integer",
|
||||
Description: "Year",
|
||||
Format: "int64",
|
||||
Example: 2020,
|
||||
},
|
||||
"month": {
|
||||
Type: "integer",
|
||||
Description: "Month",
|
||||
Format: "int64",
|
||||
Example: 12,
|
||||
},
|
||||
"day": {
|
||||
Type: "integer",
|
||||
Description: "Day",
|
||||
Format: "int64",
|
||||
Example: 13,
|
||||
},
|
||||
"hour": {
|
||||
Type: "integer",
|
||||
Description: "Hour of the day in range 0-24",
|
||||
Format: "int64",
|
||||
Example: 9,
|
||||
},
|
||||
"minute": {
|
||||
Type: "integer",
|
||||
Description: "Minute",
|
||||
Format: "int64",
|
||||
Example: 30,
|
||||
},
|
||||
"seconds": {
|
||||
Type: "integer",
|
||||
Description: "Second",
|
||||
Format: "int64",
|
||||
Example: 30,
|
||||
},
|
||||
"milliSeconds": {
|
||||
Type: "integer",
|
||||
Description: "Milliseconds",
|
||||
Format: "int64",
|
||||
Example: 123,
|
||||
},
|
||||
"dateTime": {
|
||||
Type: "string",
|
||||
Description: "Full date time",
|
||||
Format: "date-time",
|
||||
Example: "2020-12-13T09:30:30+01:00",
|
||||
},
|
||||
"date": {
|
||||
Type: "string",
|
||||
Description: "Date string",
|
||||
Example: "13/12/2020",
|
||||
},
|
||||
"time": {
|
||||
Type: "string",
|
||||
Description: "Time string",
|
||||
Example: "09:30",
|
||||
},
|
||||
"timeZone": {
|
||||
Type: "string",
|
||||
Description: "TimeZone of the result",
|
||||
Example: "Europe/Berlin",
|
||||
},
|
||||
"dayOfWeek": {
|
||||
Type: "string",
|
||||
Description: "The day of the week",
|
||||
Example: "Monday",
|
||||
},
|
||||
"dstActive": {
|
||||
Type: "boolean",
|
||||
Description: "Boolean describing whether DST is applied and active in that timezone",
|
||||
Example: false,
|
||||
},
|
||||
},
|
||||
AdditionalProperties: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return components
|
||||
}
|
||||
|
||||
func GetPaths() map[string]*api.Path {
|
||||
paths := map[string]*api.Path{
|
||||
"/Time/current/zone": {
|
||||
GET: &api.Method{
|
||||
Function: TimeCurrentZone,
|
||||
Tags: tags,
|
||||
Summary: "Gets the current time of a time zone.",
|
||||
Parameters: []*api.Parameters{
|
||||
{
|
||||
Name: "timeZone",
|
||||
In: "query",
|
||||
Description: "Full IANA time zone names.",
|
||||
Schema: &api.ParametersSchema{
|
||||
Type: "string",
|
||||
},
|
||||
Example: "Europe/Berlin",
|
||||
AllowReserved: true,
|
||||
},
|
||||
},
|
||||
Responses: map[int]*api.Response{
|
||||
200: {
|
||||
Description: "Current time",
|
||||
Content: map[string]*api.ResponseContent{
|
||||
"application/json": {
|
||||
Schema: &api.ResponseSchema{
|
||||
Ref: "#/components/schemas/CurrentTime",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
400: {
|
||||
Description: "Error message",
|
||||
Content: map[string]*api.ResponseContent{
|
||||
"application/json": {
|
||||
Schema: &api.ResponseSchema{
|
||||
Type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return paths
|
||||
}
|
81
apiTime/time.go
Normal file
81
apiTime/time.go
Normal file
@ -0,0 +1,81 @@
|
||||
package apiTime
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type dateTimeResponse struct {
|
||||
Year int `json:"year,omitempty"`
|
||||
Month int `json:"month,omitempty"`
|
||||
Day int `json:"day,omitempty"`
|
||||
Hour int `json:"hour,omitempty"`
|
||||
Minute int `json:"minute,omitempty"`
|
||||
Seconds int `json:"seconds,omitempty"`
|
||||
MilliSeconds int `json:"milliSeconds,omitempty"`
|
||||
DateTime string `json:"dateTime,omitempty"`
|
||||
Date string `json:"date,omitempty"`
|
||||
Time string `json:"time,omitempty"`
|
||||
TimeZone string `json:"timeZone,omitempty"`
|
||||
DayOfWeek string `json:"dayOfWeek,omitempty"`
|
||||
DstActive bool `json:"dstActive,omitempty"`
|
||||
}
|
||||
|
||||
func TimeCurrentZone(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Language", "en")
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
|
||||
timeZone := ""
|
||||
|
||||
vals := r.URL.Query()
|
||||
parameters, ok := vals["timeZone"]
|
||||
if ok && len(parameters) == 1 {
|
||||
timeZone = parameters[0]
|
||||
}
|
||||
|
||||
if timeZone == "" {
|
||||
w.WriteHeader(400)
|
||||
fmt.Fprint(w, "{\"error\": \"invalid value for timeZone\"}")
|
||||
return
|
||||
}
|
||||
|
||||
loc, err := time.LoadLocation(timeZone)
|
||||
if err != nil {
|
||||
w.WriteHeader(400)
|
||||
fmt.Fprint(w, "{\"error\": \"invalid value for timeZone\"}")
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("%q %q\n", loc.String(), r.RemoteAddr)
|
||||
|
||||
w.WriteHeader(200)
|
||||
fmt.Fprint(w, getDateTimeResponseAsJSONString(loc))
|
||||
}
|
||||
|
||||
func getDateTimeResponse(loc *time.Location) dateTimeResponse {
|
||||
t := time.Now().In(loc)
|
||||
return dateTimeResponse{
|
||||
Year: t.Year(),
|
||||
Month: int(t.Month()),
|
||||
Day: t.Day(),
|
||||
Hour: t.Hour(),
|
||||
Minute: t.Minute(),
|
||||
Seconds: t.Second(),
|
||||
MilliSeconds: func(i int64, err error) int { return int(i) }(strconv.ParseInt(strconv.Itoa(t.Nanosecond())[:3], 10, 0)),
|
||||
DateTime: t.Format(time.RFC3339),
|
||||
Date: fmt.Sprintf("%02d/%02d/%04d", t.Month(), t.Day(), t.Year()),
|
||||
Time: fmt.Sprintf("%02d:%02d", t.Hour(), t.Minute()),
|
||||
TimeZone: loc.String(),
|
||||
DayOfWeek: t.Weekday().String(),
|
||||
DstActive: t.IsDST(),
|
||||
}
|
||||
}
|
||||
|
||||
func getDateTimeResponseAsJSONString(loc *time.Location) string {
|
||||
r, _ := json.Marshal(getDateTimeResponse(loc))
|
||||
return string(r)
|
||||
}
|
138
main.go
138
main.go
@ -1,34 +1,83 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"git.0x0001f346.de/andreas/Datetime-API/apiTime"
|
||||
"git.0x0001f346.de/andreas/api"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
var portToListenOn int = 9100
|
||||
var defaultTZ string = "Europe/Berlin"
|
||||
|
||||
type DateTimeResponse struct {
|
||||
Year int `json:"year,omitempty"`
|
||||
Month int `json:"month,omitempty"`
|
||||
Day int `json:"day,omitempty"`
|
||||
Hour int `json:"hour,omitempty"`
|
||||
Minute int `json:"minute,omitempty"`
|
||||
Seconds int `json:"seconds,omitempty"`
|
||||
MilliSeconds int `json:"milliSeconds,omitempty"`
|
||||
DateTime string `json:"dateTime,omitempty"`
|
||||
Date string `json:"date,omitempty"`
|
||||
Time string `json:"time,omitempty"`
|
||||
TimeZone string `json:"timeZone,omitempty"`
|
||||
DayOfWeek string `json:"dayOfWeek,omitempty"`
|
||||
DstActive bool `json:"dstActive,omitempty"`
|
||||
}
|
||||
const apiTitle string = "Datetime-API"
|
||||
const apiDescription string = "A simple API to get the current time for a given time zone."
|
||||
const apiVersion string = "0.1"
|
||||
const portToListenOn int = 9100
|
||||
|
||||
func main() {
|
||||
API := buildAPI()
|
||||
router := mux.NewRouter()
|
||||
|
||||
router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Language", "en")
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
fmt.Fprint(w, API.ToJSONString())
|
||||
}).Methods("GET")
|
||||
|
||||
for route, path := range API.Paths {
|
||||
if path.DELETE != nil {
|
||||
if path.DELETE.Function == nil {
|
||||
continue
|
||||
}
|
||||
router.HandleFunc(route, path.DELETE.Function).Methods("DELETE")
|
||||
}
|
||||
if path.GET != nil {
|
||||
if path.GET.Function == nil {
|
||||
continue
|
||||
}
|
||||
router.HandleFunc(route, path.GET.Function).Methods("GET")
|
||||
}
|
||||
if path.PATCH != nil {
|
||||
if path.PATCH.Function == nil {
|
||||
continue
|
||||
}
|
||||
router.HandleFunc(route, path.PATCH.Function).Methods("PATCH")
|
||||
}
|
||||
if path.POST != nil {
|
||||
if path.POST.Function == nil {
|
||||
continue
|
||||
}
|
||||
router.HandleFunc(route, path.POST.Function).Methods("POST")
|
||||
}
|
||||
if path.PUT != nil {
|
||||
if path.PUT.Function == nil {
|
||||
continue
|
||||
}
|
||||
router.HandleFunc(route, path.PUT.Function).Methods("PUT")
|
||||
}
|
||||
}
|
||||
|
||||
printStartupBanner()
|
||||
|
||||
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", portToListenOn), router))
|
||||
}
|
||||
|
||||
func buildAPI() api.API {
|
||||
fullAPI := api.GetAPIPrototype(apiTitle, apiDescription, apiVersion)
|
||||
|
||||
for route, path := range apiTime.GetPaths() {
|
||||
fullAPI.Paths[route] = path
|
||||
}
|
||||
|
||||
for name, schema := range apiTime.GetComponents().Schemas {
|
||||
fullAPI.Components.Schemas[name] = schema
|
||||
}
|
||||
|
||||
return fullAPI
|
||||
}
|
||||
|
||||
func printStartupBanner() {
|
||||
fmt.Println("********************************************")
|
||||
fmt.Println("* *")
|
||||
fmt.Println("* git.0x0001f346.de/andreas/Datetime-API *")
|
||||
@ -37,51 +86,4 @@ func main() {
|
||||
fmt.Println("")
|
||||
fmt.Printf("Listening: http://localhost:%d\n", portToListenOn)
|
||||
fmt.Println("")
|
||||
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
loc, _ := time.LoadLocation(defaultTZ)
|
||||
if r.URL.String() != "/" {
|
||||
newloc, err := time.LoadLocation(r.URL.String()[1:])
|
||||
if err == nil {
|
||||
loc = newloc
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf(
|
||||
"%q %q\n",
|
||||
loc.String(),
|
||||
r.RemoteAddr,
|
||||
)
|
||||
|
||||
w.Header().Add("Content-Language", "en")
|
||||
w.Header().Add("Content-Type", "application/json; charset=utf-8")
|
||||
w.Header().Add("Server", "git.0x0001f346.de/andreas/Datetime-API")
|
||||
fmt.Fprint(w, GetDateTimeResponseAsJSONString(loc))
|
||||
})
|
||||
|
||||
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", portToListenOn), nil))
|
||||
}
|
||||
|
||||
func GetDateTimeResponse(loc *time.Location) DateTimeResponse {
|
||||
t := time.Now().In(loc)
|
||||
return DateTimeResponse{
|
||||
Year: t.Year(),
|
||||
Month: int(t.Month()),
|
||||
Day: t.Day(),
|
||||
Hour: t.Hour(),
|
||||
Minute: t.Minute(),
|
||||
Seconds: t.Second(),
|
||||
MilliSeconds: func(i int64, err error) int { return int(i) }(strconv.ParseInt(strconv.Itoa(t.Nanosecond())[:3], 10, 0)),
|
||||
DateTime: t.Format(time.RFC3339),
|
||||
Date: fmt.Sprintf("%02d/%02d/%04d", t.Month(), t.Day(), t.Year()),
|
||||
Time: fmt.Sprintf("%02d:%02d", t.Hour(), t.Minute()),
|
||||
TimeZone: loc.String(),
|
||||
DayOfWeek: t.Weekday().String(),
|
||||
DstActive: t.IsDST(),
|
||||
}
|
||||
}
|
||||
|
||||
func GetDateTimeResponseAsJSONString(loc *time.Location) string {
|
||||
r, _ := json.Marshal(GetDateTimeResponse(loc))
|
||||
return string(r)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user