Skip to content

dominicnieto/SkylightBackend

Repository files navigation

Skylight Backend

A Swift Vapor backend server that provides sunrise and sunset forecast data from the Sunsethue API.

πŸš€ Quick Start

Run the Server

swift run SkylightBackend serve --port 8080

The server will start at http://127.0.0.1:8080

Test the API

curl "http://127.0.0.1:8080/sunrise?lat=40.7&lon=-74"

πŸ“‘ API Endpoints

GET /sunrise

Returns today's sunrise and sunset data for a given location.

Query Parameters:

  • lat (required): Latitude (-90 to 90)
  • lon (required): Longitude (-180 to 180)

Example Request:

GET /sunrise?lat=40.7&lon=-74

Example Response:

{
  "location": {
    "latitude": 40.7,
    "longitude": -74
  },
  "sunrise": {
    "type": "sunrise",
    "model_data": true,
    "quality": 0.6,
    "quality_text": "Good",
    "cloud_cover": 0.57,
    "time": "2025-11-05T11:30:00.000Z",
    "direction": 109.8,
    "magics": {
      "blue_hour": ["2025-11-05T10:53:00.000Z", "2025-11-05T11:06:00.000Z"],
      "golden_hour": ["2025-11-05T11:12:00.000Z", "2025-11-05T11:44:00.000Z"]
    }
  },
  "sunset": {
    "type": "sunset",
    "model_data": true,
    "quality": 0.53,
    "quality_text": "Good",
    "cloud_cover": 0.9,
    "time": "2025-11-05T21:49:00.000Z",
    "direction": 250.2,
    "magics": {
      "blue_hour": ["2025-11-05T22:13:00.000Z", "2025-11-05T22:25:00.000Z"],
      "golden_hour": ["2025-11-05T21:34:00.000Z", "2025-11-05T22:06:00.000Z"]
    }
  },
  "fetchedAt": "2025-11-05T21:58:47Z"
}

Error Responses:

400 Bad Request - Missing parameters:

{"error": true, "reason": "Missing required parameters: lat and lon"}

400 Bad Request - Invalid coordinates:

{"error": true, "reason": "Latitude must be between -90 and 90"}

500 Internal Server Error - Missing API key:

{"error": true, "reason": "SUNSETHUE_API_KEY not configured"}

πŸ”‘ Configuration

The server requires a Sunsethue API key set in the environment.

Create a .env file in the project root:

SUNSETHUE_API_KEY=your_api_key_here

πŸ“± iOS App Integration

Step 1: Create Swift Models

Add these models to your iOS app (they match the server response):

struct SunriseResponse: Codable {
    let location: Location
    let sunrise: SunEvent?
    let sunset: SunEvent?
    let fetchedAt: String
}

struct Location: Codable {
    let latitude: Double
    let longitude: Double
}

struct SunEvent: Codable {
    let type: String
    let modelData: Bool
    let quality: Double?
    let qualityText: String?
    let cloudCover: Double?
    let time: String
    let direction: Double
    let magics: MagicHours

    enum CodingKeys: String, CodingKey {
        case type
        case modelData = "model_data"
        case quality
        case qualityText = "quality_text"
        case cloudCover = "cloud_cover"
        case time, direction, magics
    }
}

struct MagicHours: Codable {
    let blueHour: [String]
    let goldenHour: [String]

    enum CodingKeys: String, CodingKey {
        case blueHour = "blue_hour"
        case goldenHour = "golden_hour"
    }
}

Step 2: Make the API Call

func fetchSunriseSunset(lat: Double, lon: Double) async throws -> SunriseResponse {
    // When testing locally, use your Mac's IP address
    // When deployed, use your production URL
    let url = URL(string: "http://localhost:8080/sunrise?lat=\(lat)&lon=\(lon)")!

    let (data, response) = try await URLSession.shared.data(from: url)

    guard let httpResponse = response as? HTTPURLResponse,
          httpResponse.statusCode == 200 else {
        throw URLError(.badServerResponse)
    }

    return try JSONDecoder().decode(SunriseResponse.self, from: data)
}

Step 3: Use the Data

Task {
    do {
        let sunData = try await fetchSunriseSunset(lat: 40.7, lon: -74)

        if let sunrise = sunData.sunrise {
            print("Sunrise quality: \(sunrise.qualityText ?? "Unknown")")
            print("Sunrise time: \(sunrise.time)")

            // Convert ISO8601 string to Date
            let formatter = ISO8601DateFormatter()
            if let date = formatter.date(from: sunrise.time) {
                // Now you have a Date object to display
                print("Local time: \(date)")
            }
        }
    } catch {
        print("Error fetching sun data: \(error)")
    }
}

Step 4: Testing on Device/Simulator

When testing on iOS Simulator:

  • Use http://localhost:8080 (same machine)

When testing on a physical device:

  • Make sure your device and Mac are on the same Wi-Fi
  • Find your Mac's IP address: System Settings β†’ Network
  • Use http://YOUR_MAC_IP:8080 (e.g., http://192.168.1.5:8080)
  • Add this to your Info.plist to allow local network access:
<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsLocalNetworking</key>
    <true/>
</dict>

πŸ“¦ Project Structure

SkylightBackend/
β”œβ”€β”€ Sources/SkylightBackend/
β”‚   β”œβ”€β”€ entrypoint.swift          # App entry point
β”‚   β”œβ”€β”€ configure.swift           # Server configuration
β”‚   β”œβ”€β”€ routes.swift              # API endpoint definitions
β”‚   β”œβ”€β”€ Models/
β”‚   β”‚   └── SunsethueModels.swift # Data structures
β”‚   └── Services/
β”‚       └── SunsethueService.swift # Sunsethue API client
β”œβ”€β”€ Package.swift
β”œβ”€β”€ .env                          # Environment variables (API keys)
└── README.md                     # This file

πŸ”§ Development

Build the project

swift build

Run tests

swift test

Run in Xcode

  1. Open Package.swift in Xcode
  2. Select "My Mac" as the target
  3. Press ⌘ + R to run

🌐 Deployment (Future)

When you're ready to deploy to production:

  1. Choose a hosting provider (Railway, Heroku, AWS, etc.)
  2. Update your iOS app to use the production URL
  3. Make sure to set the SUNSETHUE_API_KEY environment variable on the server
  4. Update App Transport Security settings if needed

πŸ“š Resources

About

Vapor backend for Skylight iOS app

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published