译者 | 朱先忠
策划 | 云昭
51CTO读者成长计划社群招募,咨询小助手(微信号:TTalkxiaozhuli)
ChatGPT是由人工智能研究中心AI target=_blank class=infotextkey>OpenAI创建的尖端自然语言处理模型,OpenAI公司是由埃隆·马斯克、萨姆·奥特曼和格雷格·布罗克曼共同创办的。该模型于2018年6月发布,并不断进行修改和升级,最新版本GPT-3(https://openai.com/blog/gpt-3-Apps)于2020年发布。时下最火的ChatGPT是基于GPT-3模型开发而成,并于2022年发布。ChatGPT中的“GPT”代表“Generative Pre-trained Transformer”,即生成式预训练转换器,这是一种新式复杂的深度学习架构。ChatGPT本质上使用大量的文本数据来“学习”人类语言的复杂性,从而使之能够创建常常无法与人类相区分的回复结果。ChatGPT技术基于一种称为转换器(Transformer)的神经网络,非常适合自然语言处理应用。
ChatGPT的一个关键特性是,它能够根据您在聊天框中给出的各种提示创建高质量的输出。你得到的反应感觉就像是人类产生的。使用期间,您还可以指定请求的条件。该模型是在大量的文本语料库基础上训练的,因此它可以依靠广泛的数据来回答问题、提供信息或参与由其神经网络生成的随意对话。记忆是至关重要的;然而,ChatGPT并非完美无缺。当面临超出模型知识范围的建议时,模型可能会提供不合逻辑或不合适的答复。ChatGPT的使用率有时很高;因此,有时系统可能会限制您发送的查询数量。
由于本文的主要目的是为各位提供一个全面而实际的示例,从而说明如何使用ChatGPT为REST API生成代码;因此,现在让我们首先了解一下REST API是什么。REST API是一种web服务,允许两个计算机系统通过遵循一组标准化规则在互联网上进行通信。它遵循REST体系结构,该体系结构以其无状态和客户端-服务器的特性而闻名。REST API的工作原理是客户端使用特定的URL和HTTP方法(如GET、POST、PUT或DELETE)向服务器发送请求,服务器用包含请求的数据或指示请求的操作是否成功的消息进行响应。REST API在现代web和移动应用程序中广泛使用,因为它们提供了在系统之间交换数据的标准化和高效方法。您通常可以通过阅读文档来了解有关特定API的更多信息。其中,有些API是商业性的,通常有不同的定价计划。这也意味着,发出有关API请求是需要特定Bearer令牌的。
现在,我们来关注最有趣的部分,即在ChatGPT的帮助下,我们将尝试使用C#语言来创建一个功能齐全的REST API来实现学生信息的管理。
在本节中,我们将让ChatGPT编写一个用于管理学生的功能完备的REST API,包括创建、删除和修改学生记录等功能。要做到这一点,我们应该先建立一个“学生控制器(StudentsController)”,该控制器将具有API端点,还有一个“学生类(Student)”,该类将具有所需的字段,如Id、名称和年龄等。我们在这里的唯一工作是生成逻辑性及结构良好的查询,随着我们逐步构建API,这些查询将变得越来越复杂。让我们开始吧。
下面是一个用C#管理学生的RESTful API示例。此API将使用HTTP方法GET、POST、PUT和DELETE对学生资源列表执行CRUD(创建、读取、更新、删除)操作。
首先,让我们定义一个“学生类”来表示学生资源:
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public string Email { get; set; }
}
接下来,让我们创建一个StudentsController类来处理HTTP请求:
[Route("api/students")]
public class StudentsController : Controller
{
private static List<Student> students = new List<Student>
{
new Student { Id = 1, Name = "John Smith", Age = 20, Email = "john.smith@example.com" },
new Student { Id = 2, Name = "Jane Doe", Age = 19, Email = "jane.doe@example.com" },
new Student { Id = 3, Name = "Bob Johnson", Age = 21, Email = "bob.johnson@example.com" }
};
[HttpGet]
public IActionResult GetAllStudents()
{
return Ok(students);
}
[HttpGet("{id}")]
public IActionResult GetStudent(int id)
{
var student = students.FirstOrDefault(s => s.Id == id);
if (student == null)
{
return NotFound();
}
return Ok(student);
}
[HttpPost]
public IActionResult CreateStudent([FromBody] Student student)
{
student.Id = students.Max(s => s.Id) + 1;
students.Add(student);
return CreatedAtAction(nameof(GetStudent), new { id = student.Id }, student);
}
[HttpPut("{id}")]
public IActionResult UpdateStudent(int id, [FromBody] Student student)
{
var existingStudent = students.FirstOrDefault(s => s.Id == id);
if (existingStudent == null)
{
return NotFound();
}
existingStudent.Name = student.Name;
existingStudent.Age = student.Age;
existingStudent.Email = student.Email;
return NoContent();
}
[HttpDelete("{id}")]
public IActionResult DeleteStudent(int id)
{
var student = students.FirstOrDefault(s => s.Id == id);
if (student == null)
{
return NotFound();
}
students.Remove(student);
return NoContent();
}
此StudentsController类定义以下端点:
注意:对于CreateStudent和UpdateStudent方法,我们使用[FromBody]属性将请求体反序列化为Student对象。
还要注意,学生列表是静态的,并用一些示例数据进行了初始化。但是,在真实场景中,这些数据可能存储在数据库或其他持久性存储中。
最后,我们使用HTTP状态代码200 OK、201 Created、204 No Content和404 Not Found来指示每个操作的结果。
以下是Student类的更新版本,其中包含一些附加的属性:
public class Student
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public string Email { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
}
在该类的更新版本中,我们添加了以下属性:
这些附加的属性可以提供有关学生的更多信息,并可用于API中的筛选、排序和搜索操作。
以下是Student类的更新版本,其中包含学生所学科目的附加属性:
public class Student
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public string Email { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
public List<string> SubjectsTaken { get; set; }
}
在这个更新版本的类中,我们添加了一个名为SubjectsTaken的属性,它是一个字符串列表,表示学生所学科目的名称。此属性可用于按学生所学科目查询和筛选学生。
您可以像这样向列表中添加科目:
var student = new Student
{
Id = 1,
FirstName = "John",
LastName = "Doe",
Age = 20,
Email = "john.doe@example.com",
Address = "123 Main St",
City = "Anytown",
State = "CA",
ZipCode = "12345",
SubjectsTaken = new List<string> { "Math", "Science", "History" }
};
而且,您可以像这样检索给定学生的科目列表:
var student = GetStudent(1);
var subjects = student.SubjectsTaken;
以下是Student类的更新版本,其中SubjectsTaken属性被替换为包含Id、Name、Teacher和Credits属性的新对象Subject:
public class Subject
{
public int Id { get; set; }
public string Name { get; set; }
public string Teacher { get; set; }
public int Credits { get; set; }
}
public class Student
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public string Email { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
public List<Subject> SubjectsTaken { get; set; }
}
在这个类的更新版本中,我们用包含Id、Name、Teacher和Credits属性的新对象Subject替换了SubjectsTaken属性。这种新结构可以提供有关学生所学科目的更详细信息,并且可以用于根据特定科目的属性筛选和查询学生。
您可以将科目添加到SubjectsTaken列表,如下所示:
var student = new Student
{
Id = 1,
FirstName = "John",
LastName = "Doe",
Age = 20,
Email = "john.doe@example.com",
Address = "123 Main St",
City = "Anytown",
State = "CA",
ZipCode = "12345",
SubjectsTaken = new List<Subject>
{
new Subject { Id = 1, Name = "Math", Teacher = "Mr. Smith", Credits = 4 },
new Subject { Id = 2, Name = "Science", Teacher = "Ms. Jones", Credits = 3 }
}
};
您可以检索给定学生的科目列表,如下所示:
var student = GetStudent(1);
var subjects = student.SubjectsTaken;
public enum State
{
AL, AK, AZ, AR, CA, CO, CT, DE, FL, GA, HI, ID, IL, IN, IA, KS, KY, LA, ME,
MD, MA, MI, MN, MS, MO, MT, NE, NV, NH, NJ, NM, NY, NC, ND, OH, OK, OR, PA,
RI, SC, SD, TN, TX, UT, VT, VA, WA, WV, WI, WY
}
public class Student
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public string Email { get; set; }
public string Address { get; set; }
public string City { get; set; }
public State State { get; set; }
public string ZipCode { get; set; }
public List<Subject> SubjectsTaken { get; set; }
}
在该类的更新版本中,我们用名为State的枚举替换了State属性。State枚举包含状态缩写列表,并为State属性提供类型安全性。
您可以这样设置学生的State属性:
var student = new Student
{
Id = 1,
FirstName = "John",
LastName = "Doe",
Age = 20,
Email = "john.doe@example.com",
Address = "123 Main St",
City = "Anytown",
State = State.CA,
ZipCode = "12345",
SubjectsTaken = new List<Subject>
{
new Subject { Id = 1, Name = "Math", Teacher = "Mr. Smith", Credits = 4 },
new Subject { Id = 2, Name = "Science", Teacher = "Ms. Jones", Credits = 3 }
}
};
您可以像这样检索给定学生的State属性:
var student = GetStudent(1);
var state = student.State;
以下是Student类的更新版本,其中包括Id、FirstName和Email属性的验证:
public class Student
{
private int _id;
private string _firstName;
private string _email;
public int Id
{
get { return _id; }
set
{
if (value <= 0)
{
throw new ArgumentException("Id must be greater than zero.");
}
_id = value;
}
}
public string FirstName
{
get { return _firstName; }
set
{
if (string.IsNullOrEmpty(value))
{
throw new ArgumentException("First name cannot be null or empty.");
}
_firstName = value;
}
}
public string LastName { get; set; }
public int Age { get; set; }
public string Email
{
get { return _email; }
set
{
if (string.IsNullOrEmpty(value))
{
throw new ArgumentException("Email cannot be null or empty.");
}
_email = value;
}
}
public string Address { get; set; }
public string City { get; set; }
public State State { get; set; }
public string ZipCode { get; set; }
public List<Subject> SubjectsTaken { get; set; }
}
在这个类的更新版本中,我们为Id、FirstName和Email属性添加了私有字段,并为其相应的setter方法添加了验证逻辑。Id属性必须大于零,FirstName和Email属性不能为null或空。如果任何这些验证检查失败,将引发ArgumentException异常。
您可以像这样创建一个新的学生对象:
var student = new Student
{
Id = 1,
FirstName = "John",
LastName = "Doe",
Age = 20,
Email = "john.doe@example.com",
Address = "123 Main St",
City = "Anytown",
State = State.CA,
ZipCode = "12345",
SubjectsTaken = new List<Subject>
{
new Subject { Id = 1, Name = "Math", Teacher = "Mr. Smith", Credits = 4 },
new Subject { Id = 2, Name = "Science", Teacher = "Ms. Jones", Credits = 3 }
}
};
如果尝试使用无效数据创建新的学生对象,将引发ArgumentException异常:
var invalidStudent = new Student
{
Id = 0, // throws ArgumentException
FirstName = "", // throws ArgumentException
LastName = "Doe",
Age = 20,
Email = "", // throws ArgumentException
Address = "123 Main St",
City = "Anytown",
State = State.CA,
ZipCode = "12345",
SubjectsTaken = new List<Subject>()
};
这里是StudentsController类的更新版本,它使用异步方法:
[ApiController]
[Route("api/[controller]")]
public class StudentsController : ControllerBase
{
private readonly IStudentRepository _studentRepository;
public StudentsController(IStudentRepository studentRepository)
{
_studentRepository = studentRepository;
}
[HttpGet]
public async Task<ActionResult<IEnumerable<Student>>> GetAllStudents()
{
var students = await _studentRepository.GetAllStudentsAsync();
return Ok(students);
}
[HttpGet("{id}")]
public async Task<ActionResult<Student>> GetStudentById(int id)
{
var student = await _studentRepository.GetStudentByIdAsync(id);
if (student == null)
{
return NotFound();
}
return Ok(student);
}
[HttpPost]
public async Task<ActionResult<Student>> CreateStudent(Student student)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
await _studentRepository.AddStudentAsync(student);
return CreatedAtAction(nameof(GetStudentById), new { id = student.Id }, student);
}
[HttpPut("{id}")]
public async Task<IActionResult> UpdateStudent(int id, Student student)
{
if (id != student.Id)
{
return BadRequest();
}
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var existingStudent = await _studentRepository.GetStudentByIdAsync(id);
if (existingStudent == null)
{
return NotFound();
}
await _studentRepository.UpdateStudentAsync(student);
return NoContent();
}
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteStudent(int id)
{
var existingStudent = await _studentRepository.GetStudentByIdAsync(id);
if (existingStudent == null)
{
return NotFound();
}
await _studentRepository.DeleteStudentAsync(existingStudent);
return NoContent();
}
}
在该类的更新版本中,我们将异步关键字async添加到与IStudentRepository交互的操作方法中。我们还在调用异步方法之前添加了await关键字,以等待结果完成后再继续。
如果action方法返回一个值,我们将其包装为ActionResult<T>类型,其中“T”是返回值的类型。如果发生错误,我们将返回适当的ActionResult,例如BadRequest()或NotFound()。
注意:IStudentRepository接口也必须更新,以包含其方法的异步版本。以下是更新后的IStudentRepository的示例:
public interface IStudentRepository
{
Task<IEnumerable<Student>> GetAllStudentsAsync();
Task<Student> GetStudentByIdAsync(int id);
Task AddStudentAsync(Student student);
Task UpdateStudentAsync(Student student);
Task DeleteStudentAsync(Student student);
}
在这个版本的接口中,我们为每个方法添加了异步关键字,并将返回类型更改为Task<T>,其中“T”是返回值的类型。这允许调用代码使用await关键字等待方法完成。
在本文中,我们使用ChatGPT构建了一个REST API,这是使用ASP.NET Core和C#编程语言实现的,用于实现学生信息的管理。此API仅是一个Web服务的基本实现版本,它通过提供几个不同的端点来实现CRUD(创建、读取、更新、删除)操作,以管理学生列表。实现过程中,ChatGPT能够向Student类添加基本验证,并使代码异步。除此之外,当我们需要Subject属性的新对象时,这个AI工具能够很容易将状态属性的类型更改为枚举类型,并创建了一个全新的类。总之,它工作得很好,创建了功能齐全的类、控制器和存储库。
在我看来,ChatGPT应该被视为编程辅助工具,尤其是对于简单和重复的任务,因为它可以使这些任务自动化,并推荐更高效和有效的编程技术。因此,它可以使程序员节省时间,从而使他们可以利用这些时间来解决更具挑战性和创造性的编程任务。然而,我也认为,使用它作为人类编程技能的补充,而不是替代是很重要的,因为它通常无法在复杂的情况下提供最佳解决方案。
至于ChatGPT的威力,我相信这篇文章足以证明。如果你是开发人员,可以将ChatGPT用于其他各种场景下,例如验证或测试代码。你甚至可以使用它在Python/ target=_blank class=infotextkey>Python中生成代码。当前,许多公司已经在研究将ChatGPT集成到其平台上的方法了。
总之,ChatGPT是一种令人印象深刻的人工智能语言模型,它有可能彻底改变我们的编程方式,虽然它可能无法完全取代人类程序员,不过这个模型一定可以被视为一种宝贵的辅助资源来使用。
原文链接:https://dzone.com/articles/create-a-rest-api-in-c-using-chatgpt
朱先忠,51CTO社区编辑,51CTO专家博客、讲师,潍坊一所高校计算机教师,自由编程界老兵一枚。