diff --git a/.pullapprove.yml b/.pullapprove.yml
index ddd01beebed..95fb1c38a25 100644
--- a/.pullapprove.yml
+++ b/.pullapprove.yml
@@ -417,6 +417,7 @@ groups:
'aio/content/guide/http-request-data-from-server.md',
'aio/content/guide/http-security-xsrf-protection.md',
'aio/content/guide/http-send-data-to-server.md',
+ 'aio/content/guide/http-server-communication.md',
'aio/content/guide/http-setup-server-communication.md',
'aio/content/guide/http-test-requests.md',
'aio/content/guide/http-track-show-request-progress.md',
diff --git a/aio/content/guide/http-server-communication.md b/aio/content/guide/http-server-communication.md
new file mode 100644
index 00000000000..eb7c11ff284
--- /dev/null
+++ b/aio/content/guide/http-server-communication.md
@@ -0,0 +1,254 @@
+# HTTP Server communication
+
+Most front-end applications need to communicate with a server over the HTTP protocol, to download or upload data and access other back-end services.
+
+## Setup for server communication
+
+Before you can use `HttpClient`, you need to import the Angular `HttpClientModule`.
+Most apps do so in the root `AppModule`.
+
+
+
+You can then inject the `HttpClient` service as a dependency of an application class, as shown in the following `ConfigService` example.
+
+
+
+The `HttpClient` service makes use of [observables](guide/glossary#observable "Observable definition") for all transactions.
+You must import the RxJS observable and operator symbols that appear in the example snippets.
+These `ConfigService` imports are typical.
+
+
+
+
+
+You can run the that accompanies this guide.
+
+The sample app does not require a data server.
+It relies on the [Angular *in-memory-web-api*](https://github.com/angular/angular/tree/main/packages/misc/angular-in-memory-web-api), which replaces the *HttpClient* module's `HttpBackend`.
+The replacement service simulates the behavior of a REST-like backend.
+
+Look at the `AppModule` *imports* to see how it is configured.
+
+
+
+## Requesting data from a server
+
+Use the [`HttpClient.get()`](api/common/http/HttpClient#get) method to fetch data from a server.
+The asynchronous method sends an HTTP request, and returns an Observable that emits the requested data when the response is received.
+The return type varies based on the `observe` and `responseType` values that you pass to the call.
+
+The `get()` method takes two arguments; the endpoint URL from which to fetch, and an *options* object that is used to configure the request.
+
+
+
+options: {
+ headers?: HttpHeaders | {[header: string]: string | string[]},
+ observe?: 'body' | 'events' | 'response',
+ params?: HttpParams|{[param: string]: string | number | boolean | ReadonlyArray<string | number | boolean>},
+ reportProgress?: boolean,
+ responseType?: 'arraybuffer'|'blob'|'json'|'text',
+ withCredentials?: boolean,
+}
+
+
+
+Important options include the *observe* and *responseType* properties.
+
+* The *observe* option specifies how much of the response to return
+* The *responseType* option specifies the format in which to return data
+
+
+
+Use the `options` object to configure various other aspects of an outgoing request.
+In adding headers, for example, the service set the default headers using the `headers` option property.
+
+Use the `params` property to configure a request with [TTP URL parameters, and the `reportProgress` option to listen for progress events when transferring large amounts of data.
+
+
+
+Applications often request JSON data from a server.
+In the `ConfigService` example, the app needs a configuration file on the server, `config.json`, that specifies resource URLs.
+
+
+
+To fetch this kind of data, the `get()` call needs the following options: `{observe: 'body', responseType: 'json'}`.
+These are the default values for those options, so the following examples do not pass the options object.
+Later sections show some of the additional option possibilities.
+
+
+
+The example conforms to the best practices for creating scalable solutions by defining a re-usable [injectable service](guide/glossary#service "service definition") to perform the data-handling functionality.
+In addition to fetching data, the service can post-process the data, add error handling, and add retry logic.
+
+The `ConfigService` fetches this file using the `HttpClient.get()` method.
+
+
+
+The `ConfigComponent` injects the `ConfigService` and calls the `getConfig` service method.
+
+Because the service method returns an `Observable` of configuration data, the component *subscribes* to the method's return value.
+The subscription callback performs minimal post-processing.
+It copies the data fields into the component's `config` object, which is data-bound in the component template for display.
+
+
+
+
+
+### Starting the request
+
+For all `HttpClient` methods, the method doesn't begin its HTTP request until you call `subscribe()` on the observable the method returns.
+
+This is true for *all* `HttpClient` *methods*.
+
+
+
+You should always unsubscribe from an observable when a component is destroyed.
+
+
+
+All observables returned from `HttpClient` methods are *cold* by design.
+Execution of the HTTP request is *deferred*, letting you extend the observable with additional operations such as `tap` and `catchError` before anything actually happens.
+
+Calling `subscribe()` triggers execution of the observable and causes `HttpClient` to compose and send the HTTP request to the server.
+
+Think of these observables as *blueprints* for actual HTTP requests.
+
+
+
+In fact, each `subscribe()` initiates a separate, independent execution of the observable.
+Subscribing twice results in two HTTP requests.
+
+
+
+const req = http.get<Heroes>('/api/heroes');
+// 0 requests made - .subscribe() not called.
+req.subscribe();
+// 1 request made.
+req.subscribe();
+// 2 requests made.
+
+
+
+
+
+
+
+### Requesting a typed response
+
+Structure your `HttpClient` request to declare the type of the response object, to make consuming the output easier and more obvious.
+Specifying the response type acts as a type assertion at compile time.
+
+
+
+Specifying the response type is a declaration to TypeScript that it should treat your response as being of the given type.
+This is a build-time check and doesn't guarantee that the server actually responds with an object of this type.
+It is up to the server to ensure that the type specified by the server API is returned.
+
+
+
+To specify the response object type, first define an interface with the required properties.
+Use an interface rather than a class, because the response is a plain object that cannot be automatically converted to an instance of a class.
+
+
+
+Next, specify that interface as the `HttpClient.get()` call's type parameter in the service.
+
+
+
+
+
+When you pass an interface as a type parameter to the `HttpClient.get()` method, use the [RxJS `map` operator](guide/rx-library#operators) to transform the response data as needed by the UI.
+You can then pass the transformed data to the [async pipe](api/common/AsyncPipe).
+
+
+
+The callback in the updated component method receives a typed data object, which is easier and safer to consume:
+
+
+
+To access properties that are defined in an interface, you must explicitly convert the plain object you get from the JSON to the required response type.
+For example, the following `subscribe` callback receives `data` as an Object, and then type-casts it in order to access the properties.
+
+
+
+.subscribe(data => this.config = {
+ heroesUrl: (data as any).heroesUrl,
+ textfile: (data as any).textfile,
+});
+
+
+
+
+
+
+
+observe and response types
+
+The types of the `observe` and `response` options are *string unions*, rather than plain strings.
+
+
+
+options: {
+ …
+ observe?: 'body' | 'events' | 'response',
+ …
+ responseType?: 'arraybuffer'|'blob'|'json'|'text',
+ …
+}
+
+
+
+This can cause confusion.
+For example:
+
+
+
+// this works
+client.get('/foo', {responseType: 'text'})
+
+// but this does NOT work
+const options = {
+ responseType: 'text',
+};
+client.get('/foo', options)
+
+
+
+In the second case, TypeScript infers the type of `options` to be `{responseType: string}`.
+The type is too wide to pass to `HttpClient.get` which is expecting the type of `responseType` to be one of the *specific* strings.
+`HttpClient` is typed explicitly this way so that the compiler can report the correct return type based on the options you provided.
+
+Use `as const` to let TypeScript know that you really do mean to use a constant string type:
+
+
+
+const options = {
+ responseType: 'text' as const,
+};
+client.get('/foo', options);
+
+
+
+
+
+### Reading the full response
+
+In the previous example, the call to `HttpClient.get()` did not specify any options.
+By default, it returned the JSON data contained in the response body.
+
+You might need more information about the transaction than is contained in the response body.
+Sometimes servers return special headers or status codes to indicate certain conditions that are important to the application workflow.
+
+Tell `HttpClient` that you want the full response with the `observe` option of the `get()` method:
+
+
+
+Now `HttpClient.get()` returns an `Observable` of type `HttpResponse` rather than just the JSON data contained in the body.
+
+The component's `showConfigResponse()` method displays the response headers as well as the configuration:
+
+
+
+As you can see, the response object has a `body` property of the correct type.
+
+@reviewed 2023-02-27