使用ChatGPT在C#中创建一个REST API

315 阅读12分钟

ChatGPT是OpenAI创建的一个尖端自然语言处理模型,OpenAI是由Elon Musk、Sam Altman和Greg Brockman创立的人工智能研究中心。该模型于2018年6月公布,并不断进行修改和升级,最新的版本GPT-3将于2020年发布。ChatGPT是由GPT-3制成的,早在2022年就已发布。ChatGPT中的 "GPT "代表 "生成性预训练转化器",是指该模型的深度学习架构。ChatGPT基本上使用大量的文本数据来 "学习 "人类语言的复杂性,使其能够创造出经常无法与人类区分的答复。ChatGPT技术是基于一种被称为转化器的神经网络,它非常适合自然语言处理应用。

ChatGPT对您在聊天框中给出的各种提示创造高质量输出的能力是其关键特征之一。你得到的回应感觉就像由人生成的一样。你还可以指定你的请求的条件。该模型是在庞大的文本语料库中训练出来的,因此它可以依靠广泛的数据来回答问题,提供信息,或参与由其神经网络生成的休闲对话。关键是要记住;然而,ChatGPT并非完美无缺。当面对超出模型知识领域的建议时,模型可能会提供不合逻辑的或不合适的答复。ChatGPT的使用率有时很高,正因为如此,你能发送的查询次数有时会有限制。

现在,由于本文的主要目的是给你一个全面的实践例子,说明ChatGPT如何用于生成REST API的代码,让我们首先了解什么是REST API。REST API是一种网络服务,它允许两个计算机系统通过遵循一套标准化的规则,在互联网上相互通信。它遵循REST架构,该架构以其无状态和客户端-服务器性质而闻名。REST API的工作原理是,客户端使用特定的URL和HTTP方法向服务器发送请求,如GETPOSTPUT 、或DELETE ,而服务器则以包含所请求的数据或表明所请求的操作是否成功的消息来回应。REST APIs在现代网络和移动应用中被广泛使用,因为它们提供了一种标准化的、有效的系统间数据交换方法。你通常可以通过阅读文档来了解更多关于一个特定的API。有些API是商业性的,通常有不同的定价计划。这也意味着,提出请求需要一个不记名令牌。

现在有趣的部分来了--在ChatGPT的帮助下,用C#创建一个功能齐全的REST API来管理学生,所以继续阅读。

创建API

在这一节中,我们将让ChatGPT编码一个全功能的REST API来管理学生,包括创建、删除和修改学生记录。要做到这一点,我们应该有一个 "students控制器",它有API端点,还有一个 "students类",它有需要的字段,如 "ID"、"姓名 "和 "年龄"。我们在这里唯一的工作是进行有逻辑的、结构良好的查询,随着我们逐个部分地建立API,查询会逐渐变得复杂。让我们开始吧。

用C#写一个用于管理学生的REST API

这里有一个用C#写的管理学生的RESTful API的例子。这个API将使用HTTP方法GET,POST,PUT, 和DELETE 来对学生资源列表执行CRUD(创建、读取、更新、删除)操作。

首先,让我们定义一个 "学生类 "来代表一个学生资源:

C#

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请求:

C#

[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 类定义了以下端点:

  • GET /api/students:返回一个所有学生的列表。
  • GET /api/students/{id}:通过ID返回一个单一的学生资源。
  • POST /api/students:创建一个新的学生资源。
  • PUT /api/students/{id}:更新现有学生资源的ID。
  • DELETE /api/students/{id}:删除一个现有的学生资源的ID。

注意: 我们使用[FromBody] 属性将请求主体反序列化为一个 "学生对象",用于CreateStudentUpdateStudent 方法。

还要注意的是,学生列表是静态的,并用一些样本数据进行初始化。在真实世界的场景中,这些数据可能会被存储在数据库或其他持久性存储中。

最后,我们使用HTTP状态代码200 OK、201 Created、204 No Content和404 Not Found来表示每个操作的结果。

为学生类添加更多属性

下面是 "学生类 "的更新版本,增加了一些属性:

C#

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; }
}

在这个更新版本的类中,我们添加了以下属性:

  • FirstName:学生的名字。
  • LastName:学生的姓氏。
  • Address:学生的街道地址。
  • City:学生居住的城市。
  • State:学生居住的州。
  • ZipCode:学生的地址的邮政编码。

这些额外的属性可以提供关于学生的更多信息,对于API中的过滤、排序和搜索操作非常有用。

给学生类添加另一个属性

关于学生所学的科目

下面是 "学生类 "的更新版本,其中有一个关于学生所学科目的额外属性:

C#

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 的属性,它是一个字符串列表,代表学生所学科目的名称。这个属性对于通过学生所学的科目来查询和过滤学生非常有用。

你可以像这样把科目添加到列表中:

C#

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" }
};

而且,你可以像这样检索一个给定学生的科目列表:

C#

var student = GetStudent(1);
var subjects = student.SubjectsTaken;

将SubjectTaken改为一个名为Subject的对象

包含属性Id、Name、Teacher和Credit

下面是 "学生类 "的更新版本,其中SubjectsTaken 属性被替换为一个新的对象Subject,包含Id,Name,Teacher, 和Credits 属性:

C#

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 属性的新对象主体取代了SubjectsTaken 属性。这个新的结构可以提供关于学生所学科目的更详细的信息,它对于根据特定的科目属性过滤和查询学生非常有用。

你可以这样把一个科目添加到SubjectsTaken 列表中:

C#

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 }
    }
};

而你可以像这样检索一个给定学生的科目列表:

C#

var student = GetStudent(1);
var subjects = student.SubjectsTaken;

将学生类中的State属性改为Enum

C#

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 属性:

C#

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 属性:

C#

var student = GetStudent(1);
var state = student.State;

添加验证,使IDFirstNameEmail 成为强制性的。

下面是学生类的一个更新版本,其中包括对Id,FirstName, 和Email 属性的验证:

C#

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 属性必须大于零,FirstNameEmail 属性不能为空或空。如果任何这些验证检查失败,将抛出一个ArgumentException

你可以像这样创建一个新的学生对象:

C#

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

C#

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 类的一个更新版本,它使用了异步方法:

C#

[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();
    }
}

在这个更新版本的类中,我们在与IStudentRepository 交互的动作方法中添加了异步关键字。我们还在调用异步方法之前添加了 await 关键字,以等待结果完成后再继续。

如果动作方法返回一个值,我们把它包装在ActionResult<T> ,其中 "T "是返回值的类型。如果发生错误,我们会返回一个适当的ActionResult ,如BadRequest()NotFound()

注意IStudentRepository 接口也必须被更新,以包括其方法的异步版本。下面是一个例子,说明更新后的IStudentRepository 可能是什么样子:

C#

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.NETCore和C#编程语言来管理学生。这个API是一个网络服务的基本实现,它实现了CRUD(创建、读取、更新、删除)操作,通过提供几个不同的端点来管理学生列表。ChatGPT能够为学生类添加基本验证,并使代码异步化。除此之外,这个人工智能工具还轻松地将状态属性的类型改为枚举,并在我们需要一个新的对象作为主题属性时创建了一个全新的类。总而言之,它做得很好,创建了功能齐全的类,一个控制器和一个存储库。

在我看来,ChatGPT作为一种编程辅助工具应该被认真对待,特别是对于简单和重复的任务,因为它可以将其自动化,并推荐更高效和有效的编程技术。因此,它可以使程序员节省时间,他们可以用这些时间来解决更具挑战性和创造性的编程任务。然而,我也认为,重要的是把它作为人类编程技能的补充,而不是替代,因为它常常无法在复杂情况下提供最佳解决方案。至于它的力量,我相信这篇文章足以证明ChatGPT的力量,即使是对最大的怀疑论者来说也是如此。如果你是一名开发人员,你可以将ChatGPT用于其他各种用例,如验证或测试代码。你甚至可以用它来生成Python中的代码。许多公司已经在寻找将ChatGPT整合到他们平台的方法。

总之,ChatGPT是一个令人印象深刻的人工智能语言模型,有可能彻底改变我们的编程方式,虽然它可能无法完全取代人类程序员,但它肯定可以被视为一种宝贵的资源。