View Javadoc
1   /*
2    * Copyright (c) 2023. Roland T. Lichti, Kaiserpfalz EDV-Service.
3    *
4    * This program is free software: you can redistribute it and/or modify
5    * it under the terms of the GNU General Public License as published by
6    * the Free Software Foundation, either version 3 of the License, or
7    * (at your option) any later version.
8    *
9    * This program is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   * GNU General Public License for more details.
13   *
14   * You should have received a copy of the GNU General Public License
15   * along with this program.  If not, see <https://www.gnu.org/licenses/>.
16   */
17  
18  package de.kaiserpfalzedv.services.sms77.client;
19  
20  import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
21  
22  import java.util.Set;
23  
24  import org.springframework.cloud.openfeign.FeignClient;
25  import org.springframework.web.bind.annotation.GetMapping;
26  import org.springframework.web.bind.annotation.PostMapping;
27  import org.springframework.web.bind.annotation.RequestParam;
28  
29  import de.kaiserpfalzedv.services.sms77.model.Balance;
30  import de.kaiserpfalzedv.services.sms77.model.NumberFormatCheckResult;
31  import de.kaiserpfalzedv.services.sms77.model.Sms;
32  import de.kaiserpfalzedv.services.sms77.model.SmsResult;
33  import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
34  import io.github.resilience4j.ratelimiter.annotation.RateLimiter;
35  import io.github.resilience4j.retry.annotation.Retry;
36  import io.micrometer.core.annotation.Counted;
37  import io.micrometer.core.annotation.Timed;
38  import jakarta.validation.constraints.NotBlank;
39  import jakarta.validation.constraints.NotNull;
40  import jakarta.validation.constraints.Size;
41  
42  /**
43   * <p>
44   * Sms77Client -- The client for accessing the webservice.
45   * </p>
46   *
47   * <p>
48   * This is the client for accessing the API of the sms77 paid webservice. You need an Api-Key. This client has a spring boot application.yaml included which will rely on certain environment variables to be set. These are:
49   * </p>
50   *
51   * <dl>
52   * <dt>SMS77_API_URL</dt>
53   * <dd><em>(optional)</em>The URI for the SMS77.io api. Normally there is no reason to give another URI than {@literal https://gateway.sms77.io}. And that URI is the default when nothing else is specified./</dd>
54   * <dt>SMS77_API_KEY</dt>
55   * <dd>The API key from sms77.io. For development you should generate a sandbox api key to cut costs - but your mileage may vary.</dd>
56   * </dl>
57   *
58   * <p>
59   * For the time being the API does not throw any sms77 specific exceptions since the sms77 API always returns HTTP 200. You have to check the return objects of the calls to find out if there has something happened.
60   * </p>
61   *
62   * @author rlichti {@literal <rlichti@kaiserpfalz-edv.de>}
63   * @version 4.0.0  2024-09-22
64   * @since 3.0.0  2023-01-17
65   */
66  @FeignClient(name = "sms77", configuration = Sms77ClientConfig.class, path = "/api")
67  @SuppressWarnings("JavadocLinkAsPlainText")
68  @RateLimiter(name = "sms77client")
69  public interface Sms77Client {
70      /**
71       * Sends the SMS.
72       *
73       * @param sms The SMS to be sent. The same SMS can address multiple users.
74       * @return The result of the SMS sending.
75       */
76      @Timed("sms77.send-sms-json.time")
77      @Counted("sms77.send-sms-json.count")
78      @Retry(name = "sendSMS")
79      @CircuitBreaker(name = "sendSMS")
80      @PostMapping(value = "/sms", consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE)
81      SmsResult sendSMS(@NotNull final Sms sms);
82  
83      /**
84       * Sends the given text to the numbers specified.
85       *
86       * @param number A set of destinations for the SMS.
87       * @param text   The text of the SMS.
88       * @return
89       */
90      @Timed("sms77.send-sms-query.time")
91      @Counted("sms77.send-sms-query.count")
92      @Retry(name = "sendSMS")
93      @CircuitBreaker(name = "sendSMS")
94      @PostMapping(value = "/sms", consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE)
95      SmsResult sendSMS(
96              @Size(min = 1, max = 10) @RequestParam("to") @NotNull final Set<String> number,
97  
98              @Size(max = 1520) @RequestParam("text") @NotNull final String text);
99  
100     /**
101      * To check the current credits to use on this API you can call the balance and
102      * get the current credits.
103      *
104      * @return The current account balance of your sms77.io account.
105      */
106     @Timed("sms77.balance.time")
107     @Counted("sms77.balance.count")
108     @Retry(name = "balanceSMS")
109     @CircuitBreaker(name = "balanceSMS")
110     @GetMapping(value = "/balance", consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE)
111     Balance balance();
112 
113     /**
114      * <p>
115      * Check if the given numbers are formatted correctly. There will be no check,
116      * if the numbers are valid. This
117      * <p>
118      * check only validates the number format and not if the number is used or even
119      * active.
120      * </p>
121      *
122      * <p>
123      * This is a very ugly API call since the numbers need to be formated as single
124      * string with a comma as
125      * delimiter.
126      * </p>
127      *
128      * <p>
129      * Consider something as Set.of("49123231","124323131").join(",") ...
130      * </p>
131      *
132      * @param numbersWithComma The numbers to check, delimited by a comma.
133      * @return The format check result.
134      */
135     @Timed("sms77.number-format-check.multi.time")
136     @Counted("sms77.number-format-check.multi.count")
137     @Retry(name = "lookupSMS")
138     @CircuitBreaker(name = "lookupSMS")
139     @GetMapping(value = "/lookup", consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE)
140     Set<NumberFormatCheckResult> checkMultipleNumberFormats(
141             @RequestParam("number") @NotBlank final String numbersWithComma);
142 
143     /**
144      * <p>
145      * Checks the format of a single number.
146      * </p>
147      *
148      * <p>
149      * This function only checks, if the number format is correct. There is no check
150      * if the number is assigned or
151      * even activ.
152      * </p>
153      *
154      * @param number the number which format should be checked.
155      * @return The format check result.
156      */
157     @Timed("sms77.number-format-check.multi.time")
158     @Counted("sms77.number-format-check.multi.count")
159     @Retry(name = "checkNumberFormatSMS")
160     @CircuitBreaker(name = "checkNumberFormatSMS")
161     @GetMapping(value = "/lookup", consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE)
162     NumberFormatCheckResult checkNumberFormat(@RequestParam("number") @NotBlank final String number);
163 }