Request weather from caiyunapp.com in 10 lines of code.
10 行代码搞定彩云天气 API。
中文版本,请访问这里。
- Introduction
- Before you start
- Requirements
- Installation
- Quick starts
- Making your API request
- Performing your request
- Working with API response
- Measurement and unit converting
- Localization
- License
- Disclaimer
CaiyunWeather
is a wrapper for weather service from caiyunapp.com, written in and availble for Swift.
Different from default JSON Serializer method, CaiyunWeather
keeps all content as objects and mostly codable.
You can also define almost everything during your request and result handling.
CaiyunWeather
supports decoding API-fetched data to weather content as CYResponse
object, and encoding your CYResponse
object to locally saved data.
Therefore, a built-in method of caching weather content is provided, which means you can cut down your remote API calls and save your costs!
- You have to request a valid token from http://caiyunapp.com/ (
Chinese
) for yourself. Always keep your token secret and safe! - You are highly recommended to firstly read the API documentation (
Chinese
) from caiyunapp.com.
- Swift 5.0 or later
- Xcode 11 or later
- iOS 10 or later / macOS 10.12 or later
To install CaiyunWeather
using the Swift Package Manager, add it as a dependency into your Package.swift
file:
let package = Package(
...
dependencies: [
.package(url: "https://github.com/YuanLinStudio/CaiyunWeather.git", from: "1.0.0")
],
...
)
Use the code below to perform a request to caiyunapp.com and get the returned data decoded as CYResponse
object:
import CaiyunWeather
let token: String = "your-token-here"
// the place's coordinate of which you want to request weather
let coordinate = CYCoordinate(latitude: 31.025785475418274, longitude: 121.4474754473953)
// declare an request
let request = CYRequest(token: token, coordinate: coordinate)
// request the data
request.perform { response, source, error in
guard let response = response, error == nil else {
print(error.debugDescription)
return
}
print(response)
// your subsequent actions for `CYResponse?` result ...
}
All API-related options are defined in CYRequest.endpoint
. Please read API documentation - API Request (Chinese
) before choosing your request options.
All options are shown below:
Path of parameter | Description | Type | Default value |
---|---|---|---|
CYRequest.endpoint.token |
Your valid API token. | String! |
nil |
CYRequest.endpoint.coordinate |
The place's coordinate you want to request weather of. | CYCoordinate |
.defaultCoordinate as (0, 0) |
CYRequest.endpoint.language |
The displaying language of the response. | CYEndpoint.RequestLanguage |
.chineseSimplified |
CYRequest.endpoint.measurementSystem |
The unit system of the response. | CYEndpoint.MeasurementSystem (equal to CYUnit ) |
.metric |
CYRequest.endpoint.shouldIncludeAlerts |
Would you like to receive weather alerts in your response. | Bool |
true |
CYRequest.endpoint.hourlyLength |
How many hours would you like to receive hourly weather content. | Int |
48 |
CYRequest.endpoint.dailyLength |
How many days would you like to receive daily weather content. | Int |
5 |
CYRequest.endpoint.file |
The target file of the response. You are not recommended to change this parameter. | String |
"weather.json" |
CYRequest.endpoint.version |
API version. You are not recommended to change this parameter. | String |
"v2.5" |
To alter a parameter, initialize your CYRequest
object (recommended with let
statement), and use <path> = <value>
to make changes. Or, you may define a CYEndpoint
object and make your alternations, then pass it to CYRequest
object by <yourCYRequestObject>.endpoint = <yourCYEndpointObject>
.
Use CYRequest.endpoint.url
to get the URL after your alternation if in need. Note it can be nil
if your haven't passed in a token.
CYCoordinate
is a type alias forCLLocationCoordinate2D
in Apple'sCoreLocation
Framework, with extensions conformed toCodable
andEquatable
for coding options. You may also initialize one with longitude and latitude. Use.defaultCoordinate
to get a defaultCYCoordinate
object as (0, 0).To get user's location or a pin from map, please use
CoreLocation
orMapKit
to get the coordinate.
You may also redefine the data expiration, queue on which to perform actions or caching options if needed.
All options are shown below:
Path of parameter | Description | Type | Default value |
---|---|---|---|
CYRequest.expiration |
How long the local data is valid. | TimeInterval |
5 * 60 |
CYRequest.queue |
On which queue to perform CYRequest actions. |
DispatchQueue |
.global(qos: .background) |
CYRequest.localContentUrl |
Where to save API-returned cached data. | URL |
.cachesDirectory |
To alter a parameter, initialize your CYRequest
object (recommended with let
statement), and use <path> = <value>
to make changes.
Locally cached files will be saved in CYRequest.localContentUrl
with files named <longitude in %.4f>,<latitude in %.4f>
. This cannot be changed currently.
If you don't have the above two requirements (just keep them as default), or you would prefer overwriting parameters after they are initialized, you may use convenient initializers to quickly start up with your request.
The three initializing statements below are equal:
let token: String = "your-token-here"
let coordinate = CYCoordinate(latitude: 31.025785475418274, longitude: 121.4474754473953)
let request = CYRequest(token: token, coordinate: coordinate)
let token: String = "your-token-here"
let coordinate = CYCoordinate(latitude: 31.025785475418274, longitude: 121.4474754473953)
let endpoint = CYEndpoint(token: token, coordinate: coordinate)
let request = CYRequest()
request.endpoint = endpoint
let token: String = "your-token-here"
let coordinate = CYCoordinate(latitude: 31.025785475418274, longitude: 121.4474754473953)
var endpoint = CYEndpoint()
endpoint.token = token
endpoint.coordinate = coordinate
let request = CYRequest()
request.endpoint = endpoint
You should perform your request to get weather contents, either from remote or local.
Before continuing, make sure you have finished your request initialization.
Use CYRequest.perform(completionHandler: @escaping (CYResponse?, CYRequest.DataSource, Error?) -> Void)
to perform your request by auto choosing target. That means, The local cached data will be fetched if the following 3 conditions are met:
- the local cached file exists with no decoding errors; and
- it is for the coordinate you are requiring (rounded to
%.4f
, about 100 meters in distance); and - it is not expired.
Elsewise, a new data will be fetched from remote API and then cached.
CYRequest.DataSource
as parameter for the completionHandler
receives the target from which the data is fetched. .local
means local cache, while .remote
means remote API.
You may use CYRequest.perform(from dataSource: CYRequest.DataSource, completionHandler: @escaping (CYResponse?, CYRequest.DataSource, Error?) -> Void)
if you want to perform your request towards an explicit target. Set dataSource
to .local
if you want to fatch data from local cache, or .remote
from remote API.
You may use CYRequest.fetchData(from dataSource: CYRequest.DataSource, completionHandler: @escaping (Data?, Error?) -> Void)
if you want to fatch data without decoding it to CYResponse
object. This shall only be used for debugging and internal using.
An example JSON file is included in this package for debugging use. Call CYRequest.fetchExampleData(completionHandler: @escaping (Data?, Error?) -> Void)
to get it.
The example JSON file is a response from caiyunapp.com API, at date of 2021-04-14 and coordinate of (112.8641, 35.4904), which is located in Jincheng, Shanxi, China.
Not recommended. Note that dataTask
s are internally wrapped into perform
and fatchData
, so you should mostly use them instead.
However, if you would prefer to hard-code your URL or you need to do so, the code below may help you.
let url = "your.valid.url/for/api/requests"
URLSession.shared.dataTask(with: url) { (data, urlResponse, error) in
// deal with data ...
}
.resume()
Content received by perform
are ready-to-use and DO NOT need to decode. Skip this section and go ahead.
If you have your data ready (either fetched with fatchData
, fetched with dataTask
, or loaded from local cache), you may use CYRequest.decode(_ data: Data, completionHandler: @escaping (CYResponse?, CYError?) -> Void)
to decode your data to CYResponse
object.
Before continuing, you are highly recommended to read the API documentation (
Chinese
) to have a brief outline of the response content.
The default contents are very long, that means few people will use all of them. Therefore, you are very welcomed to define your own data model, with an adaptor from CYResponse
.
Some instructions about content types and return types are as follows. You are encouraged to read them all together, but here's an alternation for you: just skip this section and continue, come back when you meet problems.
CYContent
defines some common types for weather content, which are handy to reuse.
Type | Description | Prpoerties |
---|---|---|
CYContent.Datetime1970Based |
time |
|
CYContent.DatetimeServerType |
time |
|
CYContent.LifeIndex<T> |
Life indices with optional properties of type T . |
ultraviolet , comfort , carWashing , coldRisk , dressing |
CYContent.Wind |
speed , direction |
|
CYContent.Wind.WindSpeed |
value , description |
|
CYContent.Wind.WindDirection |
value , description |
|
CYContent.AirQuality |
Optional properties. | pm25 , pm10 , o3 , so2 , no2 , co , aqi , description |
CYContent.Phenomenon |
Enumeration. | All cases defined in API documentation - Phenomenon Codes |
Type | Description | Prpoerties |
---|---|---|
CYContent.CountryRelated<T> |
chn , usa |
|
CYContent.IndexWithDescription<T> |
index , description |
|
CYContent.AverageAndExtremum<T> |
average , maximum , minimum |
extension
them to better serve you!
If you have used perform
or decode
function above, your content will now be CYResponse?
object. Don't forget to unwrap your content. If there's no error, your content will contain all objects returned and decoded from remote API. CYResponse
and most nested objects are defined as struct
with let
statements to make your workspace clean and save memories of users' device.
The following tables explains CYResponse
and most nested objects. No description will be provided, as the name of them are defined easy and simple.
Property | Type | API Original Key |
---|---|---|
responseStatus |
String |
status |
version |
String |
api_version |
apiStatus |
String |
api_status |
language |
String |
lang |
unit |
CYUnit |
unit |
coordinate |
CYCoordinate |
location |
serverTime |
CYContent.Datetime1970Based |
server_time |
serverTimeZone |
CYTimeZone |
tzshift |
result |
CYResult |
result |
Property | Type | API Original Key |
---|---|---|
alert |
CYAlert |
alert |
realtime |
CYRealtime |
realtime |
minutely |
CYMinutely |
minutely |
hourly |
CYHourly |
hourly |
daily |
CYDaily |
daily |
keypoint |
String |
forecast_keypoint |
Property | Type | API Original Key |
---|---|---|
responseStatus |
String |
status |
content |
[CYAlert.AlertContent] |
content |
CYAlert.AlertContent
Property | Type | API Original Key |
---|---|---|
publishTime |
CYContent.Datetime1970Based |
pubtimestamp |
id |
String |
alertId |
status |
String |
status |
adcode |
String |
adcode |
location |
String |
location |
province |
String |
province |
city |
String |
city |
county |
String |
county |
code |
CYAlert.AlertContent.AlertCode |
code |
source |
String |
source |
title |
String |
title |
description |
String |
description |
Redefined types
Type | Description | Prpoerties |
---|---|---|
CYAlert.AlertContent.AlertCode |
type , level |
|
CYAlert.AlertContent.AlertCode.AlertType |
All cases defined in API documentation - Alert type codes | |
CYAlert.AlertContent.AlertCode.AlertLevel |
All cases defined in API documentation - Alert level codes |
Property | Type | API Original Key |
---|---|---|
responseStatus |
String |
status |
temperature |
Double |
temperature |
apparentTemperature |
Double |
apparent_temperature |
pressure |
Double |
pressure |
humidity |
Double |
humidity |
cloudrate |
Double |
cloudrate |
phenomenon |
CYContent.Phenomenon |
skycon |
visibility |
Double |
visibility |
dswrf |
Double |
dswrf |
wind |
CYContent.Wind |
wind |
precipitation |
CYRealtime.Precipitation |
precipitation |
airQuality |
CYContent.AirQuality? |
air_quality |
lifeIndex |
CYContent.LifeIndex<CYContent.IndexWithDescription<Int>> |
life_index |
Redefined types
Type | Description | Prpoerties |
---|---|---|
CYRealtime.Precipitation |
local , nearest |
|
CYRealtime.Precipitation.PrecipitationContent |
datasource and distance are optional. |
responseStatus , datasource , intensity , distance |
Property | Type | API Original Key |
---|---|---|
datasource |
String |
datasource |
description |
String |
description |
probability |
[Double] |
probability |
intensity |
[Double] |
precipitation_2h |
Property | Type | API Original Key |
---|---|---|
responseStatus |
String |
status |
description |
String |
description |
phenomenon |
[CYHourly.ValueWithDatetime<CYContent.Phenomenon>] |
skycon |
temperature |
[CYHourly.ValueWithDatetime<Double>] |
temperature |
precipitation |
[CYHourly.ValueWithDatetime<Double>] |
precipitation |
cloudrate |
[CYHourly.ValueWithDatetime<Double>] |
cloudrate |
humidity |
[CYHourly.ValueWithDatetime<Double>] |
humidity |
pressure |
[CYHourly.ValueWithDatetime<Double>] |
pressure |
wind |
[CYHourly.ValueWithDatetimeFlat<CYContent.Wind>] |
wind |
visibility |
[CYHourly.ValueWithDatetime<Double>] |
visibility |
dswrf |
[CYHourly.ValueWithDatetime<Double>] |
dswrf |
airQuality |
CYHourly.AirQuality |
air_quality |
Redefined types
Type | Description | Prpoerties |
---|---|---|
CYHourly.AirQuality |
aqi , pm25 |
Abstruct types
Type | Description | Prpoerties |
---|---|---|
CYHourly.ValueWithDatetime<T> |
datetime , value |
|
CYHourly.ValueWithDatetimeFlat<T> |
datetime , value |
Property | Type | API Original Key |
---|---|---|
responseStatus |
String |
status |
astronomy |
[CYDaily.Astronomy] |
astro |
phenomenon |
[CYDaily.ValueWithDate<CYContent.Phenomenon>] |
skycon |
phenomenonDaytime |
[CYDaily.ValueWithDate<CYContent.Phenomenon>] |
skycon_08h_20h |
phenomenonNighttime |
[CYDaily.ValueWithDate<CYContent.Phenomenon>] |
skycon_20h_32h |
temperature |
[CYDaily.AverageAndExtremumWithDate<Double>] |
temperature |
precipitation |
[CYDaily.AverageAndExtremumWithDate<Double>] |
precipitation |
pressure |
[CYDaily.AverageAndExtremumWithDate<Double>] |
pressure |
wind |
[CYDaily.AverageAndExtremumWithDate<CYContent.Wind>] |
wind |
cloudrate |
[CYDaily.AverageAndExtremumWithDate<Double>] |
cloudrate |
humidity |
[CYDaily.AverageAndExtremumWithDate<Double>] |
humidity |
dswrf |
[CYDaily.AverageAndExtremumWithDate<Double>] |
dswrf |
visibility |
[CYDaily.AverageAndExtremumWithDate<Double>] |
visibility |
airQuality |
[CYDaily.AirQuality] |
air_quality |
lifeIndex |
CYContent.LifeIndex<[CYDaily.IndexWithDescriptionWithDate<String>]> |
life_index |
Redefined types
Type | Description | Prpoerties |
---|---|---|
CYDaily.Astronomy |
date , value |
|
CYDaily.Astronomy.AstronomyContent |
sunrise , sunset |
|
CYDaily.Astronomy.AstronomyContent.AstronomyTime |
timeInterval |
|
CYDaily.AirQuality |
aqi , pm25 |
Abstruct types
Type | Description | Prpoerties |
---|---|---|
CYHourly.ValueWithDate<T> |
date , value |
|
CYHourly.AverageAndExtremumWithDate<T> |
date , value |
|
CYHourly.IndexWithDescriptionWithDate<T> |
date , value |
extension
them to better serve you!
API provides 5 unit systems for your requests. In this project, these 5 unit systems are also implemented and available for you to converting the weather values between them and more.
The following codes shows an example converting the wind speed:
let windSpeed = response.result.realtime.wind.speed.value
// get current unit system by either of these
let unitSystem = unit.system
// let unitSystem = request.endpoint.measurementSystem.system
// define a measurement
let measurement = Measurement(value: windSpeed, unit: unitSystem.windSpeed)
// convert the measurement to specified unit and get the value
let convertedSpeed = measurement.converted(to: .kilometersPerHour).value
Measurement and unit converting are implemented with Measurement
in Apple's Foundation
Framework. Please refer to Apple Developer Documentation - Measurement for more information.
Refer to CYUnit
for all defined measurement units.
extension
them to better serve you!
API provides 5 languages for your requests. In this project, some of weather contents are localized in 2 languages (en
and zh-Hans
), such as phenomenon, alert and wind.
Refer to Localizable
for more information.
extension
them to better serve you!
MIT
- This project has no direct connection with caiyunapp.com.
- caiyunapp.com is neither a sponsor nor responsible for this project.
- All rights that belong to caiyunapp.com are fully respected.