Skip to content

Commit

Permalink
Update RESTful-API section (#14)
Browse files Browse the repository at this point in the history
* Update RESTful API README

* Add Message-API source code

* Fix a few typos

* Fix typo

* Tidied up project for PR

* Switched for loop to LINQ query

* Fixed bad link

Co-authored-by: Rodger Gu <[email protected]>
  • Loading branch information
LindaBot and Rodger Gu authored Apr 14, 2022
1 parent 9e19925 commit d3365ca
Show file tree
Hide file tree
Showing 22 changed files with 968 additions and 23 deletions.
649 changes: 649 additions & 0 deletions .gitignore

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion 2. Python workshop/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Fortunately, your years of training at the Microsoft Space Academy had a course

## Exercise 1

Your first task, like almost anything involving unfamilar data, is to see what it actually looks like and get it into a more usable form for further analysis.
Your first task, like almost anything involving unfamiliar data, is to see what it actually looks like and get it into a more usable form for further analysis.

**Investigate the transmission file provided by opening the file and inserting each line of the file into a list for later use, then printing it.**
> Hint: Here's one way to [open CSV files](https://docs.python.org/3/library/csv.html#:~:text=A%20short%20usage%20example)
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#nullable disable
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using MessageAPI.Models;
using MessageAPI.Models.DTO;

namespace MessageAPI.Controllers;

[Route("api/message")]
[ApiController]
public class MessageItemController : ControllerBase
{
private readonly MessageContext _context;
private readonly ILogger<MessageItemController> _logger;

public MessageItemController(MessageContext context, ILogger<MessageItemController> logger)
{
_context = context ?? throw new ArgumentNullException(nameof(context));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}

/// <summary>
/// Gets all messages
/// </summary>
/// <returns>A response with the list of messages</returns>
[HttpGet]
public async Task<ActionResult<IEnumerable<MessageItemDTO>>> GetMessageItems()
{
var messageItems = await _context.MessageItems.ToListAsync();
return messageItems.Select(messageItem => new MessageItemDTO
{ Id = messageItem.Id, MainMessage = messageItem.MainMessage }).ToArray();
}

/// <summary>
/// Gets a single message
/// </summary>
/// <param name="id">The ID of the message to return</param>
/// <returns>The message with that ID, or a 404 response if the message does not exist</returns>
[HttpGet("{id}")]
public async Task<ActionResult<MessageItemDTO>> GetMessageItem(int id)
{
var messageItem = await _context.MessageItems.FindAsync(id);

if (messageItem == null)
{
return NotFound();
}

// Strip out the password
var messageItemDto = new MessageItemDTO { Id = messageItem.Id, MainMessage = messageItem.MainMessage };

return messageItemDto;
}

/// <summary>
/// Updates the message if it exists
/// </summary>
/// <param name="id">The message to update</param>
/// <param name="messageUpdateDto">The request body</param>
/// <param name="password">The password associated with the message</param>
/// <returns>A 404 response if the message doesn't exist, or a 204 if it has been updated</returns>
[HttpPatch("{id}")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> PatchMessageItem(int id, MessageUpdateDTO messageUpdateDto,
[FromHeader(Name = "password")] string password)
{
_logger.LogInformation("Password: {Password}", password);

// If the password doesn't match the old message password, return bad request.
var oldMessageItem = await _context.MessageItems.FindAsync(id);
if (oldMessageItem is null) return BadRequest();

if (password != oldMessageItem.Password)
{
return Unauthorized();
}

oldMessageItem.MainMessage = messageUpdateDto.MainMessage;
await _context.SaveChangesAsync();

return NoContent();
}

/// <summary>
/// Creates a new message
/// </summary>
/// <param name="messageItem">The new message item to create</param>
/// <returns>a success code if the message has been created</returns>
[HttpPost]
[ProducesResponseType(StatusCodes.Status201Created)]
public async Task<ActionResult<MessageItem>> PostMessageItem(MessageItem messageItem)
{
_context.MessageItems.Add(messageItem);
await _context.SaveChangesAsync();

return CreatedAtAction(nameof(GetMessageItem), new { id = messageItem.Id }, messageItem);
}

/// <summary>
/// Deletes a message if it exists
/// </summary>
/// <param name="id">The ID of the message to delete</param>
/// <returns>A 200 OK response</returns>
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteMessageItem(int id)
{
var messageItem = await _context.MessageItems.FindAsync(id);
if (messageItem is null)
{
// if we return not found, people who shouldn't know a message exists can find
// a message's existence from the response type
return Ok();
}

_context.MessageItems.Remove(messageItem);
await _context.SaveChangesAsync();

return Ok();
}
}
20 changes: 20 additions & 0 deletions 3. RESTful-API workshop/Message-API/MessageAPI.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.4">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="6.0.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.4" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="6.0.3" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace MessageAPI.Models.DTO;

public class MessageItemDTO
{
public int Id { get; set; }
public string? MainMessage { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace MessageAPI.Models.DTO;

public class MessageUpdateDTO
{
public string? MainMessage { get; set; }
}
13 changes: 13 additions & 0 deletions 3. RESTful-API workshop/Message-API/Models/MessageContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Microsoft.EntityFrameworkCore;

namespace MessageAPI.Models;

public class MessageContext : DbContext
{
public MessageContext(DbContextOptions<MessageContext> options)
: base(options)
{
}

public DbSet<MessageItem> MessageItems { get; set; } = default!;
}
8 changes: 8 additions & 0 deletions 3. RESTful-API workshop/Message-API/Models/MessageItem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace MessageAPI.Models;

public class MessageItem
{
public int Id { get; set; }
public string? MainMessage { get; set; }
public string? Password { get; set; }
}
34 changes: 34 additions & 0 deletions 3. RESTful-API workshop/Message-API/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Microsoft.EntityFrameworkCore;
using MessageAPI.Models;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();
builder.Services.AddDbContext<MessageContext>(opt =>
opt.UseInMemoryDatabase("Messages"));
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new() { Title = "MessageAPI", Version = "v1" });
});
builder.Services.AddLogging();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (builder.Environment.IsDevelopment())
{
// app.UseDeveloperExceptionPage();
}

app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "MessageAPI v1"));
app.UseHttpsRedirection();

app.UseAuthorization();
app.UseHttpLogging();

app.MapControllers();

app.Run();
31 changes: 31 additions & 0 deletions 3. RESTful-API workshop/Message-API/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:39533",
"sslPort": 44361
}
},
"profiles": {
"MessageAPI": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:7298;http://localhost:5250",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
4 changes: 4 additions & 0 deletions 3. RESTful-API workshop/Message-API/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# How to run
Ensure that you have [.Net 6.0 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/6.0) installed on your computer, open a terminal in this folder and run `dotnet restore` then `dotnet run`

> Understanding the API source code is not required for this module. However, this may help you with phase 2 and 3 :)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
9 changes: 9 additions & 0 deletions 3. RESTful-API workshop/Message-API/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
36 changes: 20 additions & 16 deletions 3. RESTful-API workshop/README.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,42 @@
# MSA 2022 RESTful API workshop
# RESTful API Workshop

Welcome to the RESTful API Workshop. The goal for this workshop is for you to get familar with RESTful API concepts and have some hands on experience with interactive with an API. You will perform CRUD operations, that is, Create, Read, Update and Delete operations on an API that we have created. You may use any tools to interact with the API, such as JavaScript, Python and Postman.
Welcome to the RESTful API Workshop. The goal for this workshop is for you to get familiar with RESTful API concepts and have some hands on experience with interactive with an API. You will perform CRUD operations, that is, Create, Read, Update and Delete operations on an API that we have created. You may use any tools to interact with the API, such as JavaScript, Python and Postman.

- Pre-requisite: https://docs.microsoft.com/en-us/learn/modules/build-web-api-minimal-api/

If you are not sure what tool to use to interact with the API, we recommend you to use [Postman](https://www.postman.com/), it is a GUI API platform for building and using APIs.

## Assignment
> Alternatively, you can also use the swagger UI built into the web API.
### Exercise 1: READ
> You can find the UI by visiting: [https://2022-nsmsa-phase-1-api.azurewebsites.net/swagger](https://2022-nsmsa-phase-1-api.azurewebsites.net/swagger). However, we recommend that you don't use this UI unless you are stuck.
Get a list of messages that other people have created in the API. The link to the API endpoint is: https://www.2022-nsmsa-phase-1-api.azurewebsites.net/api/message
## Assignment
### Exercise 1: READ

> Hint: For this exercise, you will need to use the HTTP GET Request.
Get a list of messages that other people have created in the API. The link to the API endpoint is: https://2022-nsmsa-phase-1-api.azurewebsites.net/api/message
> Hint: For this exercise, you will need to use the HTTP GET Request.
### Exercise 2: CREATE

Now that you have retrieved information from the API, let's try to do add something to the database via the API. Again, use the same endpoint, but a different HTTP method, post a message to the API: https://www.2022-nsmsa-phase-1-api.azurewebsites.net/api/message
The API takes in form-data with three key-value pair: Nickname, Message and Password. The nickname and message will be publicly displayed, whereas password will be used to authenticate you when you want to update or delete your message. Please do not put in the password that you have used somewhere else for this exercise.
Now that you have retrieved information from the API, let's try to do add something to the database via the API. Again, use the same endpoint, but a different HTTP method, post a message to the API: https://2022-nsmsa-phase-1-api.azurewebsites.net/api/message

> Hint: You will need to use an HTTP POST request.
The API takes in [json](https://json.org/example.html) formatted data with three key-value pair: "Nickname", "MainMessage" and "Password". The nickname and message will be publicly displayed, whereas password will be used to authenticate you when you want to update or delete your message. Please do not put in the password that you have used somewhere else for this exercise.
> Hint: You will need to use an HTTP POST request.
> Hint 2: You may also need to set your a HTTP header: "Content-Type" with the value of "application/json".
After you have received the success message, you may retrieve your information using a GET request, just like you did in exercise 1.
After you have received the success message, you may retrieve your information using a GET request, just like you did in exercise 1.

### Exercise 3: UPDATE
After you confirm that your entry is indeed living in the database. You next task is to update the message to say something else. The endpoint for this is: https://2022-nsmsa-phase-1-api.azurewebsites.net/api/message/MESSAGEID, where "MESSAGEID" is ID of the message you would like to update. In order to prevent unauthorized update by other people, you will need to input your password in the HTTP header. The API endpoint takes in json with one key-value pair: MainMessage (Which is the new message you want to update to).

After you confirm that your entry is indeed living in the database. You next task is to update the message to say something else. In order to prevent unauthorized update by other people, you will need to input your password in the HTTP header. The API endpoint takes in form-data with two key-value pair: ID (Which you can find by finding your message with the GET request) and message (Which is the new message you want to update to).

> Hint: You will want to use PATCH request for this exercise.
> Hint: You will want to use PATCH request for this exercise.
### Exercise 4: DELETE
Your last task is to delete an entry from the database. Again, you will need to authenticate by providing your password in the HTTP header. The API endpoint is: https://2022-nsmsa-phase-1-api.azurewebsites.net/api/message/MESSAGEID, where "MESSAGEID" is ID of the message you would like to delete.

Your last task is to delete an entry from the database. Again, you will need to authenticate by providing your password in the HTTP header. This API endpoint takes in form-data with simply one key-value pair: ID.

> Hint: You will want to use DELETE request for this exercise.
> Hint: You will want to use DELETE request for this exercise.
Note that your message won't get deleted from the database, as we want other students to see your message! But if you have received a 200 status code as a response, considered the task completed!

### Stuck somewhere?
Feel free to create a new discussion in our GitHub repository!
4 changes: 2 additions & 2 deletions 4. Relational DB workshop/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# MSA 2022 SQL Relational DB Workshop

Welcome to the SQL Relational DB Workshop. By now, you should be familiar with Basic Ralational Database and SQL queries.
Welcome to the SQL Relational DB Workshop. By now, you should be familiar with Basic Relational Database and SQL queries.

Here is an assignment to help you review those knowledge.
Here is an assignment to help you review your knowledge.

> 1. Write an SQL statement that lists school names, student names, and their cities only if the school and the student are in the same city and the student is not from New York.
Expand Down
Loading

0 comments on commit d3365ca

Please sign in to comment.