File size: 2,378 Bytes
6ee917b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import Foundation
import Vapor


struct DemController {
    struct Query: Content {
        let latitude: [String]
        let longitude: [String]
        let apikey: String?
        
        func validate() throws -> (latitude: [Float], longitude: [Float]) {
            let latitude = try Float.load(commaSeparated: self.latitude)
            let longitude = try Float.load(commaSeparated: self.longitude)
            
            guard latitude.count == longitude.count else {
                throw ForecastapiError.latitudeAndLongitudeSameCount
            }
            guard !latitude.isEmpty else {
                throw ForecastapiError.latitudeAndLongitudeNotEmpty
            }
            guard latitude.count <= 100 else {
                throw ForecastapiError.latitudeAndLongitudeMaximum(max: 100)
            }
            try zip(latitude, longitude).forEach { (latitude, longitude) in
                if latitude > 90 || latitude < -90 || latitude.isNaN {
                    throw ForecastapiError.latitudeMustBeInRangeOfMinus90to90(given: latitude)
                }
                if longitude > 180 || longitude < -180 || longitude.isNaN {
                    throw ForecastapiError.longitudeMustBeInRangeOfMinus180to180(given: longitude)
                }
            }
            return (latitude, longitude)
        }
    }

    func query(_ req: Request) async throws -> Response {
        try await req.ensureSubdomain("api")
        let params = req.method == .POST ? try req.content.decode(Query.self) : try req.query.decode(Query.self)
        let keyCheck = try await req.ensureApiKey("api", apikey: params.apikey)
        
        let (latitude, longitude) = try params.validate()
        await req.incrementRateLimiter(weight: 1, apikey: keyCheck.apikey)
        // Run query on separat thread pool to not block the main pool
        return try await ForecastapiController.runLoop.next().submit({
            let elevation = try zip(latitude, longitude).map { (latitude, longitude) in
                try Dem90.read(lat: latitude, lon: longitude)
            }
            var headers = HTTPHeaders()
            headers.add(name: .contentType, value: "application/json")
            return Response(status: .ok, headers: headers, body: .init(string: """
               {"elevation":\(elevation)}
               """))
        }).get()
    }
}