> For the complete documentation index, see [llms.txt](https://ios-course.cornellappdev.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ios-course.cornellappdev.com/course-content/week-5-or-networking/a3.5-chatdev-networking.md).

# A3.5: ChatDev — Networking

{% hint style="danger" %}
**Due: Monday, Apr 20, 2026 11:59 pm**
{% endhint %}

### Overview

In this assignment, you will be extending your A3 ChatDev app to integrate networking. You will be using **URLSession** (Swift's built-in networking API) to send HTTP requests to a backend endpoint to fetch and create posts, replacing the any dummy data you used in A3. You will also implement liking a post.

***

### Learning Objectives

**Developer Skills**

* **How to use Postman to test HTTP requests**
* **How to read data received from the backend to structure frontend code**
* How to work with Git and GitHub for version control
* How to read documentation from outside resources

**Course Material**

* How to send **GET** requests to a backend API using URLSession
* How to send **POST** requests to a backend API using URLSession
* How to use `async/await` to handle asynchronous networking calls
* How to create a `NetworkManager` singleton class to contain network calls
* How to decode a JSON using a `JSONDecoder` in Swift
* How to handle errors with networking calls

***

### Academic Integrity

As with any other course at Cornell, the Code of Academic Integrity will be enforced in this class. All University-standard Academic Integrity guidelines should be followed. This includes proper attribution of any resources found online, including anything that may be open-sourced by AppDev. The University guidelines for Academic Integrity can be found [here](https://theuniversityfaculty.cornell.edu/academic-integrity/).

**This assignment can be done with ONE partner.** You are also free to come to the instructors or any course staff for help. Programming forums like *Stack Overflow* or *Hacking with Swift* are allowed as long as you understand the code and are not copying it exactly. **The majority of code must be written by you or your partner.** Code written through AI means such as ChatGPT is **NOT ALLOWED**. However, you may use these resources for assistance, although we highly encourage consulting Ed Discussion or office hours instead.

***

### Getting Help

If you are stuck or need a bit of guidance, please make a post on Ed Discussion or visit office hours. **Please do not publicly post your code on Ed Discussion.**

The feedback form link is located in the Submission section of this handout.

***

### Grading Rubric

* **UI** : implements the user interface
* **F** : implements the functionality
* **EC** : extra credit

|                                                                        | Points                                                |
| ---------------------------------------------------------------------- | ----------------------------------------------------- |
| <mark style="color:$primary;">**PART I: Setting Up Networking**</mark> | <mark style="color:$primary;">**\_ / 2**</mark>       |
| F: `NetworkManager` singleton created with URLSession                  | \_ / 1                                                |
| F: `Post` model updated to be `Codable` / `Decodable`                  | \_ / 1                                                |
| <mark style="color:$primary;">**PART II: Fetching Posts**</mark>       | <mark style="color:$primary;">**\_ / 3**</mark>       |
| F: GET request fetches posts from the backend                          | \_ / 2                                                |
| F: Pull-to-refresh reloads posts                                       | \_ / 1                                                |
| <mark style="color:$primary;">**PART III: Creating a Post**</mark>     | <mark style="color:$primary;">**\_ / 3**</mark>       |
| F: POST request creates a post on the backend                          | \_ / 2                                                |
| F: Feed updates after creating a post                                  | \_ / 1                                                |
| <mark style="color:$primary;">**PART IV: Liking a Post**</mark>        | <mark style="color:$primary;">**\_ / 2**</mark>       |
| F: POST request to like a post                                         | \_ / 1                                                |
| F: ❤️ turns red if liked, number of likes goes up                      | \_ / 1                                                |
| <mark style="color:$success;">**SUBTOTAL**</mark>                      | <mark style="color:$success;">**\_ / 10**</mark>      |
| EC: POST Request to Unlike a Post                                      | + 1                                                   |
| EC: Sort by Top/New posts                                              | + 1                                                   |
| EC: Animation when liking a Post                                       | + 1                                                   |
| Deduction: Crash Tax                                                   | -1 point                                              |
| <mark style="color:$success;">**GRAND TOTAL**</mark>                   | <mark style="color:$success;">**\_ / 10 (+3)**</mark> |

***

### Getting Started

#### Using Postman

You are encouraged to use [Postman](https://www.postman.com/downloads/) to test out HTTP requests. Please take a look at the [Postman guide](/resources/tool-guides/postman.md).

#### Using Figma

The Figma designs from A3 still apply. You can find the link to the Figma [\[here\]](https://www.figma.com/design/kzgaF8pBYQLgjyWDyIzKSh/A3--ChatDev?node-id=1-1199\&t=TeP2K9BVE8BCj1QG-0). If you do not have an account, you can create one under your Cornell email.

#### Using Git

If you are having trouble understanding how we will be using Git in this course, please read the A1 handout under Understanding Git and GitHub section, or visit office hours so we can assist you. As a reminder:

1. **Stage:** `git add .`
2. **Commit:** `git commit -m "YOUR MESSAGE HERE"`
3. **Push:** `git push`

#### Opening the Project

Continue working in the same repository from A3. Your project should already contain your completed SwiftUI views from A3.

***

### Endpoints

* **Endpoint:** `https://ios-course-backend.cornellappdev.com/`

|                 | Type | Route                         | Request Body       |
| --------------- | ---- | ----------------------------- | ------------------ |
| Fetch all posts | GET  | `/api/posts/`                 | None               |
| Create a post   | POST | `/api/posts/create/`          | `message` (String) |
| Like a post     | POST | `/api/posts/{postId}/like/`   | `netId` (String)   |
| Unlike a post   | POST | `/api/posts/{postId}/unlike/` | `netId` (String)   |

***

## Part I: Setting Up Networking

#### Updating the Post Model

In A3, your `Post` model used local dummy data. Now you need to update it to work with data from the backend.

Here is an example post object in JSON fetched from the backend:

```json
{
    "id": "7m03J198pyXFBvCOLNbw",
    "likes": ["vdb23", "rs929"],
    "message": "Howdy!",
    "time": "2023-06-12T22:03:23Z"
}
```

Update your `Post` struct so that:

* It conforms to `Codable` (or at least `Decodable`)
* Its properties match the JSON keys from the backend (`id`, `likes`, `message`, `time`)
* The `time` property should remain a `Date` type — you will handle decoding this in the `NetworkManager`
* The `likes` property should be an array of strings (`[String]`)

> ⚠️ Because the backend provides its own `id`, you may need to adjust how your model handles identity (e.g., remove `let id = UUID()` and use the backend-provided `id` instead). Make sure your model still conforms to `Identifiable`.

#### Creating the NetworkManager

Create a new file called `NetworkManager.swift`. This will be a **singleton** class that contains all of your networking functions.

```swift
class NetworkManager {
    static let shared = NetworkManager()
    private init() {}

    let baseURL = "https://ios-course-backend.cornellappdev.com"

    // You will add your networking functions here
}
```

Once you are done, stage, commit, and push to GitHub.

***

## Part II: Fetching Posts

**Your task is to send a GET request using URLSession to fetch all posts from the backend.** Currently, your posts are all hard-coded dummy data. We want to be able to receive posts created by other people, so we must integrate networking.

#### Testing with Postman

Before writing any code, test the endpoint in Postman:

1. Add a new **GET** request
2. Enter the URL: `https://ios-course-backend.cornellappdev.com/api/posts/`
3. This should return a list of all posts from the backend with a **200** status code

#### Writing the Network Call

In `NetworkManager`, create a function to fetch all posts. Since we are using Swift's `async/await`, your function should be marked as `async throws` and return `[Post]`. You can decode the `time` field to a `Date` object by setting the decoder's `dateDecodingStrategy` to `.iso8601`. For example:

```swift
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
```

Make sure to handle errors properly in your code.

#### Integrating with SwiftUI

Once you have your fetch function, call it from your `ContentView` to populate the posts array. Use the `.task` modifier to trigger the fetch when the view loads. Since your networking function is `async`, you can call it directly inside `.task`

```swift
.task {
    do {
        posts = try await NetworkManager.shared.fetchPosts()
    } catch {
        print(error)
    }
}
```

Make sure your `@State` posts array updates on the main thread (SwiftUI handles this automatically when using `.task`).

#### Pull to Refresh

Add pull-to-refresh to your feed using the `.refreshable` modifier in SwiftUI:

```swift
List {
    // your content
}
.refreshable {
    // call your fetch function here
}
```

> 💡 If you are using a `ScrollView` + `LazyVStack` instead of a `List`, you can still use `.refreshable` on the `ScrollView`.

Once you are done, stage, commit, and push to GitHub.

***

### Part III: Creating a Post

**Your task is to send a POST request using URLSession to add a post to the backend.**

#### Testing with Postman

A good rule of thumb is to always use Postman before writing the code.

1. Add a new request to your collection with a **POST** method
2. Enter the URL: `https://ios-course-backend.cornellappdev.com/api/posts/create/`
3. Click on the **Body** tab, select **raw**, and change the blue dropdown from "Text" to **JSON**
4. This request expects the following body:

```json
{
    "message": "<Enter some message here>"
}
```

If successful, the server returns a **201** status code with JSON data representing the post that was just created. **You do not need to do anything with this information for this assignment**, but it is common practice for the backend to return this data. If you fetch all posts again, either through Postman or your app, you should see the new post that you created.

#### Writing the Network Call

Create a function in `NetworkManager` that uses URLSession to make the call. Remember that this is a **POST** request with a request body parameter called `message`. You will need to:

1. Create a `URLRequest` and set its `httpMethod` to `"POST"`
2. Set the `Content-Type` header to `"application/json"`
3. Encode the request body as JSON data and assign it to `httpBody`
4. Use `URLSession.shared.data(for:)` to send the request

Here is the general pattern:

```swift
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = try JSONEncoder().encode(body)
let (data, _) = try await URLSession.shared.data(for: request)
```

Proper error handling is highly recommended.

#### Integrating with SwiftUI

Hook up the "Post" button in `NewPostView` so that:

1. When the user taps "Post", it sends the POST request to the backend
2. If the call is successful, clear the text field and refresh the feed
3. Empty posts should still not be submittable (keep your `.disabled` logic from A3)

{% hint style="info" %}
Since your networking functions use `async/await`, you can wrap the call in a `Task { }` block inside your button action.
{% endhint %}

Once you are done, stage, commit, and push to GitHub.

***

### Part IV: Liking a Post

**Your task is to send a POST request using URLSession to like a post.**

#### Before Networking

First, configure the like button to be **filled** with the color **ruby** if the post's `likes` array contains your NetID. Otherwise, it should show the non-filled heart.

#### Testing with Postman

1. Add a new request to your collection with a **POST** method
2. Enter the URL: `https://ios-course-backend.cornellappdev.com/api/posts/{postId}/like/`
   * Note that `{postId}` is the ID of the post. Use string interpolation here.
3. Click on the **Body** tab, select **raw**, and change the blue dropdown from "Text" to **JSON**
4. This request expects the following body:

```json
{
    "netId": "<Enter your NetID>"
}
```

You will use your NetID (all lowercase). If the call is successful, you should receive the updated post.

#### Writing the Network Call & Integrating

Create a function in `NetworkManager` for liking a post. There are many ways you can go about this. One recommendation is to pass a boolean to the callback to indicate whether or not the call was successful. If the call is successful, make the like button filled and increment the count by 1. Additionally, you should only be able to tap on the button if it is not already filled red, so wrap your network request in an `if` statement.

You may notice that there is a delay before the button turns red when tapping on it. In apps like Instagram, usually the UI changes even if the API call fails. However, for the sake of simplicity and grading, we want the button to only turn red if the network call succeeds.

Once you are done, stage, commit, and push to GitHub.

***

## Extra Credit

{% hint style="info" %}
Extra credit will only be given if the features are **fully** implemented. These are unordered and you can choose as many as you like.
{% endhint %}

#### 1: Unlike a Post (+1 pt)

**Your task is to send a POST request using URLSession to unlike a post.** This may seem similar to Part IV, but it requires some additional frontend logic. When grading for this, we will unlike a post and refresh to make sure the backend is actually updated. If you try to unlike a post in which the given NetID does not already like it, you will get an error. You can test this out on Postman. The URL is `https://ios-course-backend.cornellappdev.com/api/posts/{postId}/unlike/`.

#### 2: Sort by Top/New Posts (+1) <a href="#id-2-sort-by-top-new-posts-1" id="id-2-sort-by-top-new-posts-1"></a>

If you take a look at the [Figma](https://www.figma.com/file/kzgaF8pBYQLgjyWDyIzKSh/A3%3A-ChatDev?type=design\&node-id=1%3A1199\&mode=design\&t=zCm1ZPIQJyLxedca-1) file, you should see a design containing the text “Top” and “New”. **Your task here is to sort the posts by the # of likes (top) and the most recent (new)**. For example, if the selected tab is “Top”, the post with the most likes will be at the top. If the selected tab is “New”, the most recent post will be at the top. Make sure that the color of the tab changes depending on what is selected.

#### 3: Like Animation (+1) <a href="#id-3-like-animation-1" id="id-3-like-animation-1"></a>

**Your task here is to add some animation when liking a post**. You could add a scaling animation similar to most social media apps or do some other cool animation. As long as there is some animation when liking a post, you will get full credit.

{% hint style="info" %}
SwiftUI makes animations easy — check out `.scaleEffect()`, `.animation()`, and `withAnimation {}`.
{% endhint %}

**Once you are done, stage, commit, and push to GitHub.**&#x20;

***

### Submission

1. Double check that all of your files are properly pushed to GitHub.
2. Clone your repository into a **separate** folder on your local computer drive.
3. Run your project and make sure that your code does not crash and everything works as needed.
4. If you are satisfied, download the TXT file and fill it out. Make sure to use the **Clone SSH path**.
5. Confirm that your `submission.txt` is formatted like the following and submit it on CMSX.

```
Name: Your Name
NetID: your_netid
GitHub Repository: git@github.coecis.cornell.edu:cs1998-601-sp26/NETID-a3.git
Extra Credit:
+1 : ____
+1 : ____
+1 : ____
```

6. Fill out this [feedback survey](https://docs.google.com/forms/d/e/1FAIpQLSeVPkDFFlFK5Zf65Ns9dOHx_VdnhNmpCTlrjUvn5HxoGIB4kA/viewform?usp=publish-editor) (worth 1 point).

{% hint style="info" %}
If you are partnered, make sure to create a group on CMS and put both names in the `submission.txt` file. Both students must fill out the feedback survey to receive credit.
{% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://ios-course.cornellappdev.com/course-content/week-5-or-networking/a3.5-chatdev-networking.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
