frankenstein 0.5.2

Telegram bot API client for Rust
Documentation
<p align="center"><img src="frankenstein_logo.png" alt="frankenstein" height="300px"></p>

[![Crates.io][s1]][ci] [![docs page][docs-badge]][docs] ![test][ga-test] ![style][ga-style]

# Frankenstein

Telegram bot API client for Rust.

It's a complete wrapper for Telegram bot API and it's up to date with version 5.3 of the API.

Frankenstein data structures (rust structs and enums) are mapped one-to-one from Telegram bot API objects and method params.

## Installation

Add this to your Cargo.toml


```toml
[dependencies]
frankenstein = "0.5"
```

## Usage

### Data structures

All objects described in the API docs have direct counterparts in the frankenstein. For example, in the docs there is [the user type](https://core.telegram.org/bots/api#user):
```
id	Integer	Unique identifier for this user or bot. This number may have more than 32 significant bits and some programming languages may have difficulty/silent defects in interpreting it. But it has at most 52 significant bits, so a 64-bit integer or double-precision float type are safe for storing this identifier.
is_bot	Boolean	True, if this user is a bot
first_name	String	User's or bot's first name
last_name	String	Optional. User's or bot's last name
username	String	Optional. User's or bot's username
language_code	String	Optional. IETF language tag of the user's language
can_join_groups	Boolean	Optional. True, if the bot can be invited to groups. Returned only in getMe.
can_read_all_group_messages	Boolean	Optional. True, if privacy mode is disabled for the bot. Returned only in getMe.
supports_inline_queries	Boolean	Optional. True, if the bot supports inline queries. Returned only in getMe.
```

In frankenstein, it's described as:

```rust
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct User {
    pub id: i64,

    pub is_bot: bool,

    pub first_name: String,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub last_name: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub username: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub language_code: Option<String>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub can_join_groups: Option<bool>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub can_read_all_group_messages: Option<bool>,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub supports_inline_queries: Option<bool>,
}
```

Optional fields are described as Option enum.

Every struct has the `new` method which used for initialization. It accepts only required fields, optional fields are set to `None`:

```rust
pub fn new(id: i64, is_bot: bool, first_name: String) -> User {
    Self {
        id,
        is_bot,
        first_name,
        last_name: None,
        username: None,
        language_code: None,
        can_join_groups: None,
        can_read_all_group_messages: None,
        supports_inline_queries: None,
    }
}
```

All fields have setter and getter methods :

```rust
...

 pub fn set_supports_inline_queries(&mut self, supports_inline_queries: Option<bool>) {
     self.supports_inline_queries = supports_inline_queries;
 }
 pub fn id(&self) -> i64 {
     self.id
 }

...
```


For method parameters, the same approach is used. The only difference for parameters is the name of the struct in frankenstein ends with `Params` postfix.

For example, parameters for `leaveChat` method:

```rust
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct LeaveChatParams {
    chat_id: ChatId,
}
```


### Making requests

To make a request to the telegram bot api:

1. Initialize the `Api` struct:

```rust
use frankenstein::Api;
use frankenstein::TelegramApi;

...

let token = "My_token";
let api = Api::new(token);
```

2. Use this api object to make requests to the Bot API:

```rust
let mut update_params = GetUpdatesParams::new();
update_params.set_allowed_updates(Some(vec!["message".to_string()]));

let result = api.get_updates(&update_params);
```

Every function returns a `Result` enum with a successful response or failed response.

See a complete example in the `examples` directory.

### Uploading files

Some methods in the API allow uploading files. In the frankenstein for this `File` struct is used:

```rust
pub enum File {
    InputFile(InputFile),
    String(String),
}

pub struct InputFile {
    path: std::path::PathBuf
}
```

It has two variants:

- `File::String` is used to pass id of the already uploaded file
- `File::InputFile` is used to upload a new file using multipart upload.


### Documentation

Frankenstein implements all telegram bot api methods. To see which parameters you should pass, check [docs.rs](https://docs.rs/frankenstein/0.5.2/frankenstein/api/trait.TelegramApi.html#provided-methods)

## Replacing the default http client

The library uses `ureq` http client by default, but it can be easily replaced with any http client of your choice:

1. `ureq` comes with a default feature (`impl`). So the feature should be disabled:

```toml
frankenstein = { version = "0.5", default-features = false }
```

2. Implement `TelegramApi` trait which requires two functions:

- `request_with_form_data` is used to upload files
- `request` is used for requests without file uploads

You can check [the default `TelegramApi` trait implementation](https://github.com/ayrat555/frankenstein/blob/aac88c01d06aa945393db7255ef2485a7c764d47/src/api_impl.rs) for `ureq`.

Also, you can take a look at the [implementation for `isahc` http client](https://github.com/ayrat555/frankenstein/blob/aac88c01d06aa945393db7255ef2485a7c764d47/examples/api_trait_implementation.rs) in the examples directory.

Without the default ureq implementation, `frankenstein` has only one dependency - `serde`.

## Contributing

1. [Fork it!]https://github.com/ayrat555/frankenstein/fork
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request

## Author

Ayrat Badykov (@ayrat555)


[s1]: https://img.shields.io/crates/v/frankenstein.svg
[docs-badge]: https://img.shields.io/badge/docs-website-blue.svg
[ci]: https://crates.io/crates/frankenstein
[docs]: https://docs.rs/frankenstein/
[ga-test]: https://github.com/ayrat555/frankenstein/actions/workflows/rust.yml/badge.svg
[ga-style]: https://github.com/ayrat555/frankenstein/actions/workflows/style.yml/badge.svg