譯者 | 朱先忠
策劃 | 云昭
51CTO讀者成長(zhǎng)計(jì)劃社群招募,咨詢小助手(微信號(hào):TTalkxiaozhuli)
一、簡(jiǎn)介
ChatGPT是由人工智能研究中心OpenAI創(chuàng)建的尖端自然語(yǔ)言處理模型,OpenAI公司是由埃隆·馬斯克、薩姆·奧特曼和格雷格·布羅克曼共同創(chuàng)辦的。該模型于2018年6月發(fā)布,并不斷進(jìn)行修改和升級(jí),最新版本GPT-3(https://openai.com/blog/gpt-3-apps)于2020年發(fā)布。時(shí)下最火的ChatGPT是基于GPT-3模型開(kāi)發(fā)而成,并于2022年發(fā)布。ChatGPT中的“GPT”代表“Generative Pre-trained Transformer”,即生成式預(yù)訓(xùn)練轉(zhuǎn)換器,這是一種新式復(fù)雜的深度學(xué)習(xí)架構(gòu)。ChatGPT本質(zhì)上使用大量的文本數(shù)據(jù)來(lái)“學(xué)習(xí)”人類語(yǔ)言的復(fù)雜性,從而使之能夠創(chuàng)建常常無(wú)法與人類相區(qū)分的回復(fù)結(jié)果。ChatGPT技術(shù)基于一種稱為轉(zhuǎn)換器(Transformer)的神經(jīng)網(wǎng)絡(luò),非常適合自然語(yǔ)言處理應(yīng)用。

ChatGPT的一個(gè)關(guān)鍵特性是,它能夠根據(jù)您在聊天框中給出的各種提示創(chuàng)建高質(zhì)量的輸出。你得到的反應(yīng)感覺(jué)就像是人類產(chǎn)生的。使用期間,您還可以指定請(qǐng)求的條件。該模型是在大量的文本語(yǔ)料庫(kù)基礎(chǔ)上訓(xùn)練的,因此它可以依靠廣泛的數(shù)據(jù)來(lái)回答問(wèn)題、提供信息或參與由其神經(jīng)網(wǎng)絡(luò)生成的隨意對(duì)話。記憶是至關(guān)重要的;然而,ChatGPT并非完美無(wú)缺。當(dāng)面臨超出模型知識(shí)范圍的建議時(shí),模型可能會(huì)提供不合邏輯或不合適的答復(fù)。ChatGPT的使用率有時(shí)很高;因此,有時(shí)系統(tǒng)可能會(huì)限制您發(fā)送的查詢數(shù)量。
由于本文的主要目的是為各位提供一個(gè)全面而實(shí)際的示例,從而說(shuō)明如何使用ChatGPT為REST API生成代碼;因此,現(xiàn)在讓我們首先了解一下REST API是什么。REST API是一種web服務(wù),允許兩個(gè)計(jì)算機(jī)系統(tǒng)通過(guò)遵循一組標(biāo)準(zhǔn)化規(guī)則在互聯(lián)網(wǎng)上進(jìn)行通信。它遵循REST體系結(jié)構(gòu),該體系結(jié)構(gòu)以其無(wú)狀態(tài)和客戶端-服務(wù)器的特性而聞名。REST API的工作原理是客戶端使用特定的URL和HTTP方法(如GET、POST、PUT或DELETE)向服務(wù)器發(fā)送請(qǐng)求,服務(wù)器用包含請(qǐng)求的數(shù)據(jù)或指示請(qǐng)求的操作是否成功的消息進(jìn)行響應(yīng)。REST API在現(xiàn)代web和移動(dòng)應(yīng)用程序中廣泛使用,因?yàn)樗鼈兲峁┝嗽谙到y(tǒng)之間交換數(shù)據(jù)的標(biāo)準(zhǔn)化和高效方法。您通常可以通過(guò)閱讀文檔來(lái)了解有關(guān)特定API的更多信息。其中,有些API是商業(yè)性的,通常有不同的定價(jià)計(jì)劃。這也意味著,發(fā)出有關(guān)API請(qǐng)求是需要特定Bearer令牌的。
現(xiàn)在,我們來(lái)關(guān)注最有趣的部分,即在ChatGPT的幫助下,我們將嘗試使用C#語(yǔ)言來(lái)創(chuàng)建一個(gè)功能齊全的REST API來(lái)實(shí)現(xiàn)學(xué)生信息的管理。
二、創(chuàng)建API
在本節(jié)中,我們將讓ChatGPT編寫(xiě)一個(gè)用于管理學(xué)生的功能完備的REST API,包括創(chuàng)建、刪除和修改學(xué)生記錄等功能。要做到這一點(diǎn),我們應(yīng)該先建立一個(gè)“學(xué)生控制器(StudentsController)”,該控制器將具有API端點(diǎn),還有一個(gè)“學(xué)生類(Student)”,該類將具有所需的字段,如Id、名稱和年齡等。我們?cè)谶@里的唯一工作是生成邏輯性及結(jié)構(gòu)良好的查詢,隨著我們逐步構(gòu)建API,這些查詢將變得越來(lái)越復(fù)雜。讓我們開(kāi)始吧。
三、用C#語(yǔ)言編寫(xiě)用于管理學(xué)生的REST API
下面是一個(gè)用C#管理學(xué)生的RESTful API示例。此API將使用HTTP方法GET、POST、PUT和DELETE對(duì)學(xué)生資源列表執(zhí)行CRUD(創(chuàng)建、讀取、更新、刪除)操作。
首先,讓我們定義一個(gè)“學(xué)生類”來(lái)表示學(xué)生資源:
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public string Email { get; set; }
}
接下來(lái),讓我們創(chuàng)建一個(gè)StudentsController類來(lái)處理HTTP請(qǐng)求:
[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類定義以下端點(diǎn):
- GET /api/students:返回所有學(xué)生的列表。
- GET /api/students/{id}:按id返回單個(gè)學(xué)生資源。
- POST /api/students:創(chuàng)建一個(gè)新的學(xué)生資源。
- PUT /api/students/{id}:按id更新現(xiàn)有學(xué)生資源。
- DELETE /api/students/{id}:按id刪除現(xiàn)有的學(xué)生資源。
注意:對(duì)于CreateStudent和UpdateStudent方法,我們使用[FromBody]屬性將請(qǐng)求體反序列化為Student對(duì)象。
還要注意,學(xué)生列表是靜態(tài)的,并用一些示例數(shù)據(jù)進(jìn)行了初始化。但是,在真實(shí)場(chǎng)景中,這些數(shù)據(jù)可能存儲(chǔ)在數(shù)據(jù)庫(kù)或其他持久性存儲(chǔ)中。
最后,我們使用HTTP狀態(tài)代碼200 OK、201 Created、204 No Content和404 Not Found來(lái)指示每個(gè)操作的結(jié)果。
四、向Student類添加更多屬性
以下是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; }
}
在該類的更新版本中,我們添加了以下屬性:
- FirstName:學(xué)生的名字。
- LastName:學(xué)生的姓。
- Address:學(xué)生的街道地址。
- City:學(xué)生居住的城市。
- State:學(xué)生所在的州。
- ZipCode:學(xué)生地址的郵政編碼。
這些附加的屬性可以提供有關(guān)學(xué)生的更多信息,并可用于API中的篩選、排序和搜索操作。
五、將另一個(gè)屬性添加到Student類
關(guān)于學(xué)生所學(xué)的科目
以下是Student類的更新版本,其中包含學(xué)生所學(xué)科目的附加屬性:
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; }
}
在這個(gè)更新版本的類中,我們添加了一個(gè)名為SubjectsTaken的屬性,它是一個(gè)字符串列表,表示學(xué)生所學(xué)科目的名稱。此屬性可用于按學(xué)生所學(xué)科目查詢和篩選學(xué)生。
您可以像這樣向列表中添加科目:
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" }
};
而且,您可以像這樣檢索給定學(xué)生的科目列表:
var student = GetStudent(1);
var subjects = student.SubjectsTaken;
六、將SubjectTake更改為名為Subject的對(duì)象
包含屬性Id、Name、Teacher和Credits
以下是Student類的更新版本,其中SubjectsTaken屬性被替換為包含Id、Name、Teacher和Credits屬性的新對(duì)象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; }
}
在這個(gè)類的更新版本中,我們用包含Id、Name、Teacher和Credits屬性的新對(duì)象Subject替換了SubjectsTaken屬性。這種新結(jié)構(gòu)可以提供有關(guān)學(xué)生所學(xué)科目的更詳細(xì)信息,并且可以用于根據(jù)特定科目的屬性篩選和查詢學(xué)生。
您可以將科目添加到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 }
}
};
您可以檢索給定學(xué)生的科目列表,如下所示:
var student = GetStudent(1);
var subjects = student.SubjectsTaken;
七、將Student類中的State屬性更改為枚舉類型
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枚舉包含狀態(tài)縮寫(xiě)列表,并為State屬性提供類型安全性。
您可以這樣設(shè)置學(xué)生的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 }
}
};
您可以像這樣檢索給定學(xué)生的State屬性:
var student = GetStudent(1);
var state = student.State;
八、為必填項(xiàng)ID、FirstName和EmailID添加校驗(yàn)器
以下是Student類的更新版本,其中包括Id、FirstName和Email屬性的驗(yàn)證:
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; }
}
在這個(gè)類的更新版本中,我們?yōu)镮d、FirstName和Email屬性添加了私有字段,并為其相應(yīng)的setter方法添加了驗(yàn)證邏輯。Id屬性必須大于零,F(xiàn)irstName和Email屬性不能為null或空。如果任何這些驗(yàn)證檢查失敗,將引發(fā)ArgumentException異常。
您可以像這樣創(chuàng)建一個(gè)新的學(xué)生對(duì)象:
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 }
}
};
如果嘗試使用無(wú)效數(shù)據(jù)創(chuàng)建新的學(xué)生對(duì)象,將引發(fā)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控制器異步
這里是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();
}
}
在該類的更新版本中,我們將異步關(guān)鍵字async添加到與IStudentRepository交互的操作方法中。我們還在調(diào)用異步方法之前添加了await關(guān)鍵字,以等待結(jié)果完成后再繼續(xù)。
如果action方法返回一個(gè)值,我們將其包裝為ActionResult<T>類型,其中“T”是返回值的類型。如果發(fā)生錯(cuò)誤,我們將返回適當(dāng)?shù)腁ctionResult,例如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);
}
在這個(gè)版本的接口中,我們?yōu)槊總€(gè)方法添加了異步關(guān)鍵字,并將返回類型更改為T(mén)ask<T>,其中“T”是返回值的類型。這允許調(diào)用代碼使用await關(guān)鍵字等待方法完成。
十、結(jié)論
在本文中,我們使用ChatGPT構(gòu)建了一個(gè)REST API,這是使用ASP.NET Core和C#編程語(yǔ)言實(shí)現(xiàn)的,用于實(shí)現(xiàn)學(xué)生信息的管理。此API僅是一個(gè)Web服務(wù)的基本實(shí)現(xiàn)版本,它通過(guò)提供幾個(gè)不同的端點(diǎn)來(lái)實(shí)現(xiàn)CRUD(創(chuàng)建、讀取、更新、刪除)操作,以管理學(xué)生列表。實(shí)現(xiàn)過(guò)程中,ChatGPT能夠向Student類添加基本驗(yàn)證,并使代碼異步。除此之外,當(dāng)我們需要Subject屬性的新對(duì)象時(shí),這個(gè)AI工具能夠很容易將狀態(tài)屬性的類型更改為枚舉類型,并創(chuàng)建了一個(gè)全新的類。總之,它工作得很好,創(chuàng)建了功能齊全的類、控制器和存儲(chǔ)庫(kù)。
在我看來(lái),ChatGPT應(yīng)該被視為編程輔助工具,尤其是對(duì)于簡(jiǎn)單和重復(fù)的任務(wù),因?yàn)樗梢允惯@些任務(wù)自動(dòng)化,并推薦更高效和有效的編程技術(shù)。因此,它可以使程序員節(jié)省時(shí)間,從而使他們可以利用這些時(shí)間來(lái)解決更具挑戰(zhàn)性和創(chuàng)造性的編程任務(wù)。然而,我也認(rèn)為,使用它作為人類編程技能的補(bǔ)充,而不是替代是很重要的,因?yàn)樗ǔo(wú)法在復(fù)雜的情況下提供最佳解決方案。
至于ChatGPT的威力,我相信這篇文章足以證明。如果你是開(kāi)發(fā)人員,可以將ChatGPT用于其他各種場(chǎng)景下,例如驗(yàn)證或測(cè)試代碼。你甚至可以使用它在Python中生成代碼。當(dāng)前,許多公司已經(jīng)在研究將ChatGPT集成到其平臺(tái)上的方法了。
總之,ChatGPT是一種令人印象深刻的人工智能語(yǔ)言模型,它有可能徹底改變我們的編程方式,雖然它可能無(wú)法完全取代人類程序員,不過(guò)這個(gè)模型一定可以被視為一種寶貴的輔助資源來(lái)使用。
原文鏈接:??https://dzone.com/articles/create-a-rest-api-in-c-using-chatgpt??
譯者介紹
朱先忠,51CTO社區(qū)編輯,51CTO專家博客、講師,濰坊一所高校計(jì)算機(jī)教師,自由編程界老兵一枚。
