Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update keys api #252

Merged
merged 23 commits into from
Feb 14, 2022
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
b11cc41
Update key API
bidoubiwa Feb 7, 2022
e5cc747
Add patch method in requests
bidoubiwa Feb 7, 2022
16ebe3a
Add missing code samples
bidoubiwa Feb 7, 2022
3245b68
Add a type for the key creation payload
bidoubiwa Feb 8, 2022
6cff92e
Merge branch 'update_api_to_task_api' of github.com:meilisearch/meili…
bidoubiwa Feb 8, 2022
d037c4b
Merge
bidoubiwa Feb 8, 2022
d87d335
Merge branch 'update_api_to_task_api' of github.com:meilisearch/meili…
bidoubiwa Feb 8, 2022
5bc9ddd
Fix linting
bidoubiwa Feb 8, 2022
a960e23
Update Sources/MeiliSearch/Client.swift
bidoubiwa Feb 8, 2022
6a113a9
Remove unecessary file
bidoubiwa Feb 8, 2022
4a98a0f
Fix key code samples
bidoubiwa Feb 8, 2022
b3d7793
Fix keys in code samples
bidoubiwa Feb 9, 2022
eaa54e3
Merge branch 'update_api_to_task_api' of github.com:meilisearch/meili…
bidoubiwa Feb 10, 2022
8713d8b
Merge branch 'update_keys_api' of github.com:meilisearch/meilisearch-…
bidoubiwa Feb 10, 2022
a1f40fd
Improve wording of expiresAt of Keys in comments
bidoubiwa Feb 10, 2022
8750dbe
Change parameters in create key and update key to correct ones
bidoubiwa Feb 10, 2022
1c54692
Change duplicated variable names to unique ones
bidoubiwa Feb 10, 2022
344ab1f
Change generic JSON encoder to constant one
bidoubiwa Feb 10, 2022
2881a0a
Add consistent usage of setValue in http request
bidoubiwa Feb 10, 2022
482a750
Improve tests made on keys
bidoubiwa Feb 10, 2022
e3703f6
Test for error code on successfull deleted key
bidoubiwa Feb 10, 2022
ca1e35e
Safe guard key tests
bidoubiwa Feb 10, 2022
026ab54
Safeguard key tests
bidoubiwa Feb 10, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 121 additions & 8 deletions .code-samples.meilisearch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -162,15 +162,128 @@ get_all_tasks_1: |-
print(error)
}
}
get_keys_1: |-
client.keys { (result: Result<Key, Swift.Error>) in
switch result {
case .success(let key):
print(key)
case .failure(let error):
print(error)
}
get_on_key_1: |-
self.client.getKey(key: d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4) { result in
brunoocasali marked this conversation as resolved.
Show resolved Hide resolved
brunoocasali marked this conversation as resolved.
Show resolved Hide resolved
switch result {
case .success(let key):
print(key)
case .failure(let error):
print(error)
}
}
get_all_keys_1: |-
self.client.getKeys() { result in
switch result {
case .success(let keys):
print(keys)
case .failure(let error):
print(error)
}
}
create_a_key_1: |-
let keyParams = KeyParams(
description: "Add documents: Products API key",
actions: ["documents.add"],
indexes: ["products"],
expiresAt: "2042-04-02T00:42:42Z"
brunoocasali marked this conversation as resolved.
Show resolved Hide resolved
)
self.client.createKey(keyParams) { result in
switch result {
case .success(let key):
print(keys)
case .failure(let error):
print(error)
}
}
update_a_key_1: |-
let keyParams = KeyParams(
description: "Add documents: Products API key",
actions: ["documents.add", "documents.delete"],
indexes: ["products", "reviews"],
expiresAt: "2042-04-02T00:42:42Z"
)
self.client.updateKey(
key: d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4
brunoocasali marked this conversation as resolved.
Show resolved Hide resolved
keyparams: keyParams
) { result in
switch result {
case .success(let key):
print(keys)
case .failure(let error):
print(error)
}
}
delete_a_key_1: |-
self.client.deleteKey(key: d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4)
brunoocasali marked this conversation as resolved.
Show resolved Hide resolved
{ result in
switch result {
case .success:
print("success")
case .failure(let error):
print(error)
}
}

security_guide_search_key_1: |-
client = MeiliSearch(host: "http://localhost:7700", apiKey: "apiKey")
client.index("patient_medical_record")
bidoubiwa marked this conversation as resolved.
Show resolved Hide resolved
.search(parameters) { (result: Result<SearchResult<Record>, Swift.Error>) in
bidoubiwa marked this conversation as resolved.
Show resolved Hide resolved
switch result {
case .success(let searchResult):
print(searchResult)
case .failure(let error):
print(error)
}
}
security_guide_update_key_1: |-
let keyParams = KeyParams(
indexes: ["doctors"]
)
self.client.updateKey(
key: d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4,
brunoocasali marked this conversation as resolved.
Show resolved Hide resolved
keyParams: keyParams,
) { result in
switch result {
case .success(let key):
print(keys)
case .failure(let error):
print(error)
}
}
security_guide_create_key_1: |-
let keyParams = KeyParams(
description: "Search patient records key",
actions: ["search"],
indexes: ["patient_medical_records"],
expiresAt: "2023-01-01T00:00:00Z""
bidoubiwa marked this conversation as resolved.
Show resolved Hide resolved
)
self.client.createKey(keyParams) { result in
switch result {
case .success(let key):
print(keys)
case .failure(let error):
print(error)
}
}
security_guide_list_keys_1: |-
self.client.getKeys() { result in
switch result {
case .success(let keys):
print(keys)
case .failure(let error):
print(error)
}
}
security_guide_delete_key_1: |-
self.client.deleteKey(key: d0552b41536279a0ad88bd595327b96f01176a60c2243e906c52ac02375f9bc4)
{ result in
switch result {
case .success:
print("success")
case .failure(let error):
print(error)
}
}
get_settings_1: |-
client.index("movies").getSettings { (result: Result<Setting, Swift.Error>) in
switch result {
Expand Down
78 changes: 73 additions & 5 deletions Sources/MeiliSearch/Client.swift
Original file line number Diff line number Diff line change
Expand Up @@ -212,17 +212,85 @@ public struct MeiliSearch {
// MARK: Keys

/**
Each instance of MeiliSearch has three keys: a master, a private, and a public. Each key has a given
set of permissions on the API routes.
Get all keys.

- parameter masterKey: Master key to access the `keys` function.
- parameter completion: The completion closure used to notify when the server
completes the query request, it returns a `Result` object that contains `Key` value.
If the request was sucessful or `Error` if a failure occured.
*/
public func keys(
public func getKeys(
_ completion: @escaping (Result<Results<Key>, Swift.Error>) -> Void) {
self.keys.getAll(completion)
}

/**
Get one key's information using the key value.

- parameter key: The key value.
- parameter completion: The completion closure used to notify when the server
completes the query request, it returns a `Result` object that contains `Key` value.
If the request was sucessful or `Error` if a failure occured.
*/
public func getKey(
key: String,
_ completion: @escaping (Result<Key, Swift.Error>) -> Void) {
self.keys.get(key: key, completion)
}

/**
Create an API key.

- parameter description: Description of the key.
- parameter actions: Actions permitted by the key.
- parameter indexes: Indexes on which the key has permissions.
- parameter expiresAt: Date in ISO-8601 format when the key is expired.
bidoubiwa marked this conversation as resolved.
Show resolved Hide resolved
- parameter completion: The completion closure used to notify when the server
completes the query request, it returns a `Result` object that contains `Key` value.
If the request was sucessful or `Error` if a failure occured.
*/
public func createKey(
_ keyParams: KeyParams,
_ completion: @escaping (Result<Key, Swift.Error>) -> Void) {
self.keys.get(completion)
self.keys.create(keyParams, completion)
}

/**
Update an API key.

- parameter key: The key value.
- parameter actions: Actions permitted by the key.
bidoubiwa marked this conversation as resolved.
Show resolved Hide resolved
- parameter indexes: Indexes on which the key has permissions.
- parameter expiresAt: Date in ISO-8601 format when the key is expired.
- parameter completion: The completion closure used to notify when the server
completes the query request, it returns a `Result` object that contains `Key` value.
If the request was sucessful or `Error` if a failure occured.
*/
public func updateKey(
key: String,
keyParams: KeyParams,
_ completion: @escaping (Result<Key, Swift.Error>) -> Void) {
self.keys.update(
key: key,
keyParams: keyParams,
completion
)
}

/**
Delete an API key.

- parameter key: The key value.
- parameter completion: The completion closure used to notify when the server
completes the query request, it returns a `Result` object that contains `Key` value.
If the request was sucessful or `Error` if a failure occured.
*/
public func deleteKey(
key: String,
_ completion: @escaping (Result<(), Swift.Error>) -> Void) {
self.keys.delete(
key: key,
completion
)
}

// MARK: Stats
Expand Down
95 changes: 92 additions & 3 deletions Sources/MeiliSearch/Keys.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,10 @@ struct Keys {
self.request = request
}

func get(_ completion: @escaping (Result<Key, Swift.Error>) -> Void) {
self.request.get(api: "/keys") { result in
func get(key: String, _ completion: @escaping (Result<Key, Swift.Error>) -> Void) {
self.request.get(api: "/keys/\(key)") { result in
switch result {
case .success(let data):

guard let data: Data = data else {
completion(.failure(MeiliSearch.Error.dataNotFound))
return
Expand All @@ -32,4 +31,94 @@ struct Keys {
}
}
}

func getAll(_ completion: @escaping (Result<Results<Key>, Swift.Error>) -> Void) {
self.request.get(api: "/keys") { result in
switch result {
case .success(let data):
guard let data: Data = data else {
completion(.failure(MeiliSearch.Error.dataNotFound))
return
}
do {
let keys: Results<Key> = try Constants.customJSONDecoder.decode(Results<Key>.self, from: data)
completion(.success(keys))
} catch {
completion(.failure(error))
}
case .failure(let error):
completion(.failure(error))
}
}
}

public func create(
_ keyParams: KeyParams,
_ completion: @escaping (Result<Key, Swift.Error>) -> Void) {
let data: Data
do {
let encoder = JSONEncoder()
bidoubiwa marked this conversation as resolved.
Show resolved Hide resolved
data = try encoder.encode(keyParams)
} catch {
completion(.failure(MeiliSearch.Error.invalidJSON))
return
}
self.request.post(api: "/keys", data) { result in
switch result {
case .success(let data):
bidoubiwa marked this conversation as resolved.
Show resolved Hide resolved
do {
let key: Key = try Constants.customJSONDecoder.decode(
Key.self,
from: data)
completion(.success(key))
} catch {
completion(.failure(error))
}
case .failure(let error):
completion(.failure(error))
}
}
}

public func update(
key: String,
keyParams: KeyParams,
_ completion: @escaping (Result<Key, Swift.Error>) -> Void) {
let data: Data
do {
let encoder = JSONEncoder()
data = try encoder.encode(keyParams)
} catch {
completion(.failure(MeiliSearch.Error.invalidJSON))
return
}
self.request.patch(api: "/keys/\(key)", data) { result in
switch result {
case .success(let data):
do {
let key: Key = try Constants.customJSONDecoder.decode(
Key.self,
from: data)
completion(.success(key))
} catch {
completion(.failure(error))
}
case .failure(let error):
completion(.failure(error))
}
}
}

public func delete(
key: String,
_ completion: @escaping (Result<(), Swift.Error>) -> Void) {
self.request.delete(api: "/keys/\(key)") { result in
switch result {
case .success:
completion(.success(()))
case .failure(let error):
completion(.failure(error))
}
}
}
}
13 changes: 7 additions & 6 deletions Sources/MeiliSearch/Model/Key.swift
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import Foundation

/**
Each instance of MeiliSearch has three keys: a master, a private, and a public.
Each key has a given set of permissions on the API routes.
*/
public struct Key: Codable, Equatable {
// MARK: Properties

/// Private key used to access a determined set of API routes.
public let `private`: String

/// Public key used to access a determined set of API routes.
public let `public`: String
public let description: String
public let key: String
public let actions: [String]
public let indexes: [String]
public let expiresAt: String?
public let createdAt: String
public let updatedAt: String
}
21 changes: 21 additions & 0 deletions Sources/MeiliSearch/Model/KeyParams.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import Foundation

/**
`KeyParams` contains all the parameters to create an API key.
*/
public struct KeyParams: Codable, Equatable {
public let description: String
public let actions: [String]
public let indexes: [String]
public let expiresAt: String?

public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(description, forKey: .description)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain this function for me (or send me some references about it), I didn't get what it will result, or how it is done (lack of swift expertise 😓)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By default, the JSON encoder of Swift considers that if one of your field is nil it means it can be removed from the JSON object.
The problem in the key route is that expiresAt is mandatory.
To workaround it I had to redefine exactly all the fields I want to be present after the encoding.

try container.encode(actions, forKey: .actions)
try container.encode(indexes, forKey: .indexes)
try container.encode(expiresAt, forKey: .expiresAt)
}

// MARK: Properties
}
Loading