# Adding Endpoints

This is mostly useful if you've managed to catch a new Telegram Bot API update
before the library can get updated. It's also a great source of information
about how the types work internally.

## Creating the Config

The first step in adding a new endpoint is to create a new Config type for it.
These belong in `configs.go`.

Let's try and add the `deleteMessage` endpoint. We can see it requires two
fields; `chat_id` and `message_id`. We can create a struct for these.

```go
type DeleteMessageConfig struct {
	ChatID    ???
	MessageID int
}
```

What type should `ChatID` be? Telegram allows specifying numeric chat IDs or
channel usernames. Golang doesn't have union types, and interfaces are entirely
untyped. This library solves this by adding two fields, a `ChatID` and a
`ChannelUsername`. We can now write the struct as follows.

```go
type DeleteMessageConfig struct {
	ChannelUsername string
	ChatID          int64
	MessageID       int
}
```

Note that `ChatID` is an `int64`. Telegram chat IDs can be greater than 32 bits.

Okay, we now have our struct. But we can't send it yet. It doesn't implement
`Chattable` so it won't work with `Request` or `Send`.

### Making it `Chattable`

We can see that `Chattable` only requires a few methods.

```go
type Chattable interface {
	params() (Params, error)
	method() string
}
```

`params` is the fields associated with the request. `method` is the endpoint
that this Config is associated with.

Implementing the `method` is easy, so let's start with that.

```go
func (config DeleteMessageConfig) method() string {
	return "deleteMessage"
}
```

Now we have to add the `params`. The `Params` type is an alias for
`map[string]string`. Telegram expects only a single field for `chat_id`, so we
have to determine what data to send.

We could use an if statement to determine which field to get the value from.
However, as this is a relatively common operation, there's helper methods for
`Params`. We can use the `AddFirstValid` method to go through each possible
value and stop when it discovers a valid one. Before writing your own Config,
it's worth taking a look through `params.go` to see what other helpers exist.

Now we can take a look at what a completed `params` method looks like.

```go
func (config DeleteMessageConfig) params() (Params, error) {
	params := make(Params)

	params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername)
	params.AddNonZero("message_id", config.MessageID)

	return params, nil
}
```

### Uploading Files

Let's imagine that for some reason deleting a message requires a document to be
uploaded and an optional thumbnail for that document. To add file upload
support we need to implement `Fileable`. This only requires one additional
method.

```go
type Fileable interface {
	Chattable
	files() []RequestFile
}
```

First, let's add some fields to store our files in. Most of the standard Configs
have similar fields for their files.

```diff
 type DeleteMessageConfig struct {
     ChannelUsername string
     ChatID          int64
     MessageID       int
+    Delete          RequestFileData
+    Thumb           RequestFileData
 }
```

Adding another method is pretty simple. We'll always add a file named `delete`
and add the `thumb` file if we have one.

```go
func (config DeleteMessageConfig) files() []RequestFile {
	files := []RequestFile{{
		Name: "delete",
		Data: config.Delete,
	}}

	if config.Thumb != nil {
		files = append(files, RequestFile{
			Name: "thumb",
			Data: config.Thumb,
		})
	}

	return files
}
```

And now our files will upload! It will transparently handle uploads whether File
is a `FilePath`, `FileURL`, `FileBytes`, `FileReader`, or `FileID`.

### Base Configs

Certain Configs have repeated elements. For example, many of the items sent to a
chat have `ChatID` or `ChannelUsername` fields, along with `ReplyToMessageID`,
`ReplyMarkup`, and `DisableNotification`. Instead of implementing all of this
code for each item, there's a `BaseChat` that handles it for your Config.
Simply embed it in your struct to get all of those fields.

There's only a few fields required for the `MessageConfig` struct after
embedding the `BaseChat` struct.

```go
type MessageConfig struct {
	BaseChat
	Text                  string
	ParseMode             string
	DisableWebPagePreview bool
}
```

It also inherits the `params` method from `BaseChat`. This allows you to call
it, then you only have to add your new fields.

```go
func (config MessageConfig) params() (Params, error) {
	params, err := config.BaseChat.params()
	if err != nil {
		return params, err
	}

	params.AddNonEmpty("text", config.Text)
	// Add your other fields

	return params, nil
}
```

Similarly, there's a `BaseFile` struct for adding an associated file and
`BaseEdit` struct for editing messages.

## Making it Friendly

After we've got a Config type, we'll want to make it more user-friendly. We can
do this by adding a new helper to `helpers.go`. These are functions that take
in the required data for the request to succeed and populate a Config.

Telegram only requires two fields to call `deleteMessage`, so this will be fast.

```go
func NewDeleteMessage(chatID int64, messageID int) DeleteMessageConfig {
	return DeleteMessageConfig{
		ChatID:    chatID,
		MessageID: messageID,
	}
}
```

Sometimes it makes sense to add more helpers if there's methods where you have
to set exactly one field. You can also add helpers that accept a `username`
string for channels if it's a common operation.

And that's it! You've added a new method.