API的实践之路:分享一个自己做的APP——Missing|青训营

81 阅读9分钟

我最开始做这个APP的想法只是想简单学习一下API接口的运用,后面在学习的过程中,发现后端的东西真的作为一个之前搞前端的人弄不明白的。磕磕碰碰,花了一天写Android,又花了三天不断调接口,才简单摸着点东西。

API

API是什么

API接口(Application Programming Interface)是用于不同软件应用程序之间进行通信和交互的一种协议或方法。它定义了通过预定义的请求和响应格式来访问和操作特定软件或服务的规则和约定。

API接口允许不同的应用程序之间相互调用和交换数据,使它们能够相互协作和共享功能。通过使用API接口,开发人员可以利用其他应用程序或服务的功能,而无需理解或处理底层实现细节。

API接口可以以多种不同的方式实现,其中最常见的是基于网络的API,通过HTTP协议传输数据。基于网络的API通常使用标准的HTTP方法(如GET、POST、PUT、DELETE等)和URI(Uniform Resource Identifier)来描述请求,并使用JSON、XML或其他格式来表示请求参数和响应数据。

例如,社交媒体平台的API接口可以提供获取用户个人资料、发布消息、评论等功能。支付网关的API接口可以提供创建支付、查询交易状态等功能。这些API接口定义了如何构造请求、以及如何解析和处理响应,从而使客户端应用程序能够与这些服务进行交互。

API接口设计的必要

  1. 实现模块化和解耦合:通过良好的API接口设计,不同模块之间可以通过定义的接口进行通信,实现模块化和解耦合。这样可以提高代码的可维护性和可扩展性,使得程序更加灵活和易于维护。
  2. 促进团队协作:在团队开发中,API接口定义了不同模块之间的约定和规范。团队成员可以根据接口进行各自的开发工作,并且在集成时能够更容易地进行协作和沟通,降低了开发过程中的沟通成本。
  3. 提供安全性和权限控制:API接口设计可以包括认证和权限控制机制,确保只有具有权限的用户可以访问和操作相关资源。通过合理设计的接口,可以有效保护敏感信息和防止未经授权的访问。
  4. 支持跨平台和跨语言集成:良好设计的API接口可以使得程序可以被其他系统或服务所使用和集成。无论是内部系统之间的集成还是与第三方服务的对接,都可以通过定义清晰的API接口来实现无缝的集成。
  5. 提升用户体验:对外提供的API接口可以使得开发者和用户可以轻松地访问和使用程序的功能。通过设计易用、一致性和高效的接口,可以提升用户体验和用户满意度。

MISSING

那么,该如何去把知识运用到实践呢?先别急,先简单做个前端

MISSING的登陆注册前端搭建

image.png

image.png

MISSING的API接口设计

GO编码的API设计
package main  
  
import (  
"bytes"  
"encoding/json"  
"fmt"  
"io/ioutil"  
"net/http"  
  
"github.com/gin-gonic/gin"  
)  
  
type User struct {  
Name string `json:"name"`  
Password string `json:"password"`  
}  
  
var userList []User  
  
func main() {  
r := gin.Default()  
  
r.POST("/user", add)  
r.GET("/user/:name", delete)  
r.GET("/user", getAllData)  
  
err := r.Run(":8080")  
if err != nil {  
fmt.Println("Failed to start server:", err)  
}  
}  
  
func add(c *gin.Context) {  
var user User  
err := c.BindJSON(&user)  
if err != nil {  
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid JSON"})  
return  
}  
  
userList = append(userList, user)  
  
c.JSON(http.StatusOK, gin.H{"message": "User added successfully"})  
}  
  
func delete(c *gin.Context) {  
name := c.Param("name")  
  
for i, user := range userList {  
if user.Name == name {  
userList = append(userList[:i], userList[i+1:]...)  
c.JSON(http.StatusOK, gin.H{"message": "User deleted successfully"})  
return  
}  
}  
  
c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})  
}  
  
func getAllData(c *gin.Context) {  
c.JSON(http.StatusOK, gin.H{"users": userList})  
}  
  
func sendRequest(method, url string, body interface{}) ([]byte, error) {  
jsonBody, _ := json.Marshal(body)  
  
req, err := http.NewRequest(method, url, bytes.NewBuffer(jsonBody))  
if err != nil {  
return nil, err  
}  
  
req.Header.Set("Content-Type", "application/json")  
  
client := &http.Client{}  
resp, err := client.Do(req)  
if err != nil {  
return nil, err  
}  
defer resp.Body.Close()  
  
responseBody, err := ioutil.ReadAll(resp.Body)  
if err != nil {  
return nil, err  
}  
  
return responseBody, nil  
}
  1. 导入所需的包。这里使用了ginnet/httpbytesencoding/jsonio/ioutil等包。
  2. 定义了User结构体,用于表示用户的属性,包括NamePassword字段。
  3. 声明了一个全局变量userList,用于存储用户信息。
  4. main函数中,创建了一个默认的gin引擎实例,并指定了路由规则。
  5. add函数中,使用BindJSON方法绑定请求中的JSON数据到user结构体,并将其添加到userList中。
  6. delete函数根据传入的用户名参数,遍历userList,找到对应的用户并将其从列表中删除。
  7. getAllData函数返回整个userList中的所有用户信息。
  8. sendRequest函数用于发送HTTP请求,支持GET、POST、PUT等不同的请求方法。
JAVA代码调用接口

由于代码百分比要求,就不给全部代码,在这给出关于POST请求的部分

public void add(String name, String password) {
    // 发送POST请求
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                URL url = new URL("http://localhost:8080//user");
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setRequestMethod("POST");
                conn.setDoInput(true);//发送POST请求必须设置允许输出
                conn.setDoOutput(true);//发送POST请求必须设置允许输入
                conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
                conn.setDoOutput(true);

                // 设置请求体参数
                String jsonInputString = "{"name": "" + name + "", "password": "" + password + ""}";

                try (OutputStream outputStream = conn.getOutputStream()) {
                    byte[] input = jsonInputString.getBytes("utf-8");
                    outputStream.write(input, 0, input.length);
                }

                int responseCode = conn.getResponseCode();
                if (responseCode == HttpURLConnection.HTTP_OK) {
                    BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                    String inputLine;
                    StringBuilder response = new StringBuilder();

                    while ((inputLine = in.readLine()) != null) {
                        response.append(inputLine);
                    }
                    // 将数据添加到本地数据库
                    SQLiteDatabase db = getWritableDatabase();
                    ContentValues values = new ContentValues();
                    values.put("name", name);
                    values.put("password", password);
                    db.insert("dp_map", null, values);
                    in.close();

                    System.out.println("Response: " + response.toString());
                } else {
                    System.out.println("Error: " + responseCode);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }).start();
}

最终(部分)实现结果

编译GO的API接口,确保http://localhost:8080/user占用

image.png MISSING Screenshot_2023-08-23-15-24-52-99_975dd6f71cc459b.jpg 注册页面

Screenshot_2023-08-23-15-25-56-23_975dd6f71cc459b.jpg 注册成功跳转至登录

Screenshot_2023-08-23-15-24-21-07_975dd6f71cc459b.jpg 登录调用API获取数据库内容

Screenshot_2023-08-23-15-24-41-39_975dd6f71cc459b.jpg 在MISSING APP内部,我的想法是设计多个恋爱小游戏,目前只有一个恋爱脑的AI五子棋,接下来是不断的打磨与升级。

总结

API设计的要点与步骤

  1. 确定目标:首先明确API的目标和用途,明确要提供的功能和服务。
  2. 定义功能:根据目标确定API的功能和接口,明确要实现的功能和需要的输入输出参数。
  3. 设计接口:根据功能定义接口,包括API的请求方法(如GET、POST)、URL路径、参数、返回结果等。
  4. 保持简洁:设计API时要尽量简洁明了,避免冗余和复杂的参数设置,使接口易于理解和使用。
  5. 统一风格:保持整个API一致的命名规范、参数传递方式、错误处理机制等,提高可读性和易用性。
  6. 考虑安全性:在设计API时考虑安全性问题,包括身份验证、数据加密、访问授权等。
  7. 考虑可扩展性:API设计时要考虑未来的扩展需求,预留合适的接口和参数,便于后续的版本升级和功能添加。
  8. 测试与文档:设计完成后,进行全面的测试,确保API的正常运行。同时提供详细的文档,包括接口说明、参数说明、示例代码等,方便用户使用和集成。

注意事项

  1. 遵循标准:在设计API时,遵循行业规范和标准,如RESTful API设计原则、HTTP协议规范等。
  2. 错误处理:API应该有良好的错误处理机制,返回合适的错误码和错误信息,方便用户排查问题。
  3. 版本管理:如果API可能会有版本更新,要考虑好版本管理策略,避免因接口变动而影响用户使用。
  4. 性能优化:在设计API时需考虑性能问题,避免不必要的资源消耗,优化响应时间和吞吐量。
  5. 文档完善:提供清晰、详细的文档,包括接口说明、参数说明、示例代码等,以便用户快速上手和集成。
  6. 监控与日志:为API添加监控和日志功能,及时发现和解决问题,提高系统的可用性和稳定性。
  7. 保持兼容性:尽量保持向前兼容,避免破坏用户已有的集成和使用方式。

感想

在学习前后端API接口的设计调用和实现的过程中,遇到了许多麻烦,百度、问朋友,快把脑子弄炸了。这一篇应该是我青训营期间最后一篇笔记了。 回顾这段时间参加字节后端青训营的学习经历,我深感这是一次珍贵的成长旅程。在青训营的课堂上,我领略了GO语言的魅力,探索了后端架构的奥秘,并发现了框架和中间件的神奇之处。这些宝贵的知识和技能,让我受益匪浅,为我的未来发展打下了坚实的基础。

GO语言作为一门现代化的编程语言,以其高效、简洁和并发性强的特点,呈现给我一个全新的世界。通过学习GO的语法规范和并发编程,我可以轻松应对简单的后端任务,并享受到开发的快乐和成就感。这种对GO语言的热爱和追求,推动着我不断学习和钻研。

在后端架构的学习过程中,我开始了一次关于系统设计的冒险探索。我了解了面向服务的架构(SOA)和微服务架构,理解了它们是如何将复杂的系统拆解成简单的模块,并实现高可用性和可扩展性的。这让我明白了系统设计的艺术,感受到了架构带来的巨大影响力。我期待着将所学应用于实际项目中,构建出稳健、高效的后端系统。

学习了Gin、Beego等框架,我感受到了它们的强大功能和便捷性,让我能够更快速地搭建和开发后端应用。中间件则为我的系统提供了额外的安全和稳定保障,让我能够以更放心的状态面对复杂的需求和挑战。

字节后端青训营的结营意味着结束,但对我来说,这只是新的起点。我将继续努力学习和实践,将所掌握的知识转化为实际应用的能力,不断提升自己在后端开发领域的水平。这段学习经历将永远成为我奋斗的动力和回忆,让我在未来的道路上更加坚定地追逐梦想。